LinuxCamp | DevOps
Обо мне: C/C++/Linux эксперт. Говорим про разработку, Linux, DevOps, сети и администрирование. Админ (реклама): @XoDefender Чат: @linuxcamp_chat Менеджер: @Spiral_Yuri Биржа: https://telega.in/c/linuxcamp_tg РКН: https://clck.ru/3RWA3C
Больше📈 Аналитический обзор Telegram-канала LinuxCamp | DevOps
Канал LinuxCamp | DevOps (@linuxcamp_tg) языкового сегмента Русский является активным участником. Сейчас сообщество объединяет 13 932 подписчиков, занимая 9 149 место в категории Технологии и приложения и 47 289 место в регионе Россия.
📊 Показатели аудитории и динамика
С момента создания невідомо проект демонстрирует стремительный рост, собрав аудиторию из 13 932 подписчиков.
Согласно последним данным от 08 июля, 2026, канал показывает стабильную активность. За последние 30 дней изменение числа участников составило -100, а за последние 24 часа — -6, при этом общий охват остаётся высоким.
- Статус верификации: Не верифицирован
- Уровень вовлечённости (ER): Средний показатель вовлечённости аудитории составляет 28.83%. В первые 24 часа после публикации контент обычно набирает 11.52% реакций от общего числа подписчиков.
- Охват публикаций: В среднем каждый пост получает 4 023 просмотров. В течение первых суток публикация набирает 1 608 просмотров.
- Реакции и взаимодействия: Аудитория активно поддерживает контент: среднее количество реакций на один пост — 23.
- Тематические интересы: Контент сосредоточен на ключевых темах, таких как linuxcamp, ядро, linux, диск, docker.
📝 Описание и контентная политика
Автор описывает ресурс как площадку для выражения субъективного мнения:
“Обо мне: C/C++/Linux эксперт. Говорим про разработку, Linux, DevOps, сети и администрирование.
Админ (реклама): @XoDefender
Чат: @linuxcamp_chat
Менеджер: @Spiral_Yuri
Биржа: https://telega.in/c/linuxcamp_tg
РКН: https://clck.ru/3RWA3C”
Благодаря высокой частоте обновлений (последние данные получены 09 июля, 2026) канал поддерживает актуальность и высокий уровень охвата публикаций. Аналитика показывает, что аудитория активно взаимодействует с контентом, что делает его важной точкой влияния в категории Технологии и приложения.
$ scp user@host:/path/to/file /local/dir
Скопируем файлы с локального компьютера на удаленный хост:
$ scp /local/dir/file user@host:/remote/dir
Скопируем файл с одного удаленного хоста на другой:
$ scp user1@host1:/remote/file user2@host2:/remote/dir
Прога sftp не требует постоянно указывать адрес ssh сервера. Вместо этого мы подключаемся к нему один раз и используем интерфейс get и put:
$ sftp user@host
sftp> get /remote/dir/file /local/dir
sftp> put /local/dir/file /remote/dir
Для передачи каталогов используем флаг "-r":
$ scp -r /local/dir user@host:/remote/dir
$ sftp> put -r /local/dir /remote/dir
Также хочется отметить, что sftp имеет важное преимущество перед обычным ftp — она не требует, чтобы на удаленном узле работал сервер FTP. Ей необходим только SSH.
LinuxCamp | #microhelp
$ tr флаг SET1 [SET2]
Сетами представлены наборы символов, с которыми tr будет работать. Второй набор не всегда используется.
Команда разбирает текст посимвольно и выполняет операцию для каждого элемента отдельно.
Флаги команды tr:
1) -d (--delete): удаляет элементы из первого набора:
$ echo "Hello 123 world" | tr -d ' a-zA-Z'
123
2) -c (--complement): обработать каждый символ, который не входит в набор "SET1":
$ echo "Hello 123 world" | tr -cd 'a-zA-Z\n'
Helloworld
В примере мы удалили все символы, которые не входят в перечисление 'a-zA-Z\n';
Таким же макаром можно все буквы удалить и оставить только цифры:
$ cat customer.csv
USA,1234567890
Canada,0987654321
$ cat customer.csv | tr -cd '0-9\n'
1234567890
0987654321
3) -s (--squeeze-repeats): cжимает повторяющиеся символы из первого набора до одного:
$ echo "Hello World" | tr -s ' '
Hello World
4) -t (--truncate-set1): обрезает первый набор до длины второго:
$ echo "abcdef" | tr -t 'abcdef' '123'
123def
Если длина первого набора больше и мы не указываем флаг, каждый последующий его символ, который (по номеру > конец "SET2"), будет заменен:
$ echo "abcdef" | tr 'abcdef' '123'
123333
При своем дефолтном поведении, программа заменяет символы из "SET1" на элементы "SET2":
$ echo "Hello World" | tr 'a-z' 'A-Z'
HELLO WORLD
Команда умеет парсить шаблоны: [:upper:], [:lower:] и т.д. Детальнее можно ознакомиться в мануале:
$ echo "hello world" | tr [:lower:] [:upper:]
HELLO WORLD
Данные на вход можно получить и через файлик. Для этого мы используем перенаправление:
$ cat infile
www.baeldung.com
$ tr 'a-z' 'A-Z' < infile
WWW.BAELDUNG.COM
Измененные данные нужно куда-то записать? Правильно, перенаправляем вывод:
$ tr 'a-z' 'A-Z' < infile > outfile
LinuxCamp | #utils
$ file linuxmint-22.1-xfce-64bit.iso
linuxmint-22.1-xfce-64bit.iso: ISO 9660 CD-ROM filesystem data (DOS/MBR boot sector) ... (bootable)
В зависимости от содержимого образ может быть загрузочным и не загрузочным. Давайте из приведенного выше описания iso-шника выведем возможные способы работы с ним:
1) он представляет собой архив - его можно распаковать;
2) он содержит файловую систему ISO9660 - его можно монтировать;
Начнем с "распакоуки". Для этого можем воспользоваться утилитой 7z:
$ sudo apt install p7zip-full
$ 7z x linux*.iso -o./extract
После завершения процесса мы вольны вносить в файловую структуру свои коррективы. После правок нужно будет заново собрать установочный iso образ. Для этого есть утилитка mkisofs, которая корректно собирает ISO9660 архивы из файлов и каталогов.
Второй способ - монтировать образ и скопировать его содержимое.
В привычном для нас понимании, монтирование относится к блочным устройствам (usb, ssd, hdd), которые содержат определенную файловую систему (exFAT, ext, zfs). Такой механизм позволяет нам получить доступ к содержимому носителей.
Но вот в чем дело, iso файл не является блочным устройством и его нельзя просто так примонтировать... Ничего, есть решение - механизм loop device.
Loop device — это виртуальное блочное устройство, которое позволяет использовать обычный ресурс с файловой системой, как физический девайс. Через него можно смонтировать образ и получить доступ к его файловой системе.
Посмотреть то, какое устройство с каким ресурсом соотносится, можно через команду losetup:
$ sudo losetup -a
/dev/loop13: [64512]:2672215 (/path/to/output.iso)
Для того, чтобы создать и монтировать "loop device", используем mount:
$ sudo mount -o loop test.iso ./mnt_point
Теперь, т.к. файловая система ISO9660 является "read-only", нам нужно скопировать все содержимое образа в отдельный каталог:
$ mkdir new_mnt_point
$ cp -rT mnt_point new_mnt_point
Далее "по уму" редактируем образ и пересобираем его с помощью mkisofs:
$ sudo mkisofs -o ./new.iso -quiet -R -b boot/grub/bios.img -no-emul-boot -boot-load-size 4 -boot-info-table ./new_mnt_point
Если все сделано правильно, на выходе мы получим "bootable" образ.
LinuxCamp | #filesystem
$ ls -l
-rw-r--r-- ... dhcpcd.conf
Команда umask (встроена в оболочку) позволяет настроить те самые права, которые будут применимы по умолчанию к ресурсам при их создании.
Ранее мы затрагивали права в:
1) разница между chmod и chown;
2) файл групп /etc/group;
3) шпаргалка по правам доступа;
Немного вспомним наши права
В общем случае права доступа в UNIX разбиты на три категории: u (user), g (group), o (other).
Каждая категория имеет три типа битов, которые различны для файлов и каталогов.
Для файлов:
r (read, 4, 100) – чтение файла.
w (write, 2, 010) – изменение файла.
x (execute, 1, 001) – выполнение файла как программы.
Для каталогов:
r (read, 4, 100) – чтение списка файлов.
w (write, 2, 010) – изменение и создание файлов в каталоге.
x (execute, 1, 001) – открытие файлов в каталоге.
Когда создаётся новый ресурс, система назначает ему максимально возможные права: файлы (666 = rw-rw-rw-), каталоги (777 = rwxrwxrwx).
Как работает umask
Суть работы команды - не добавить права, а ограничивает их, убрав заданные биты доступа.
Итоговый набор бит рассчитывается довольно просто: от максимальных прав отнимается маска.
Дефолтное значение маски обычно следующее:
$ umask
0002
Поэтому права по умолчанию для файла будут:
666 - 002 = 664
-rw-rw-r--
А для каталога:
777 - 002 = 775
drwxrwxr-x
Важное замечание: с помощью маски не получится сохранить либо исключить бит выполнения "x" для файлов. Этот флаг можно обработать только для каталогов:
$ umask 010
$ mkdir newdir
$ ls -l
drwxrw-rwx ... newdir
Напомню, что права файла рассчитываются на основе адского набора "666", где выполнение уже отключено.
Формы синтаксиса umask
У команды довольно простой синтаксис и несколько способов определения маски:
$ umask опции восьмеричная_маска
$ umask опции u=права,g=права,o=права
Посмотреть текущее значение маски можно двумя способами:
$ umask
0002
$ umask -S
u=rwx,g=rwx,o=rx
Способы задания маски
Вообще, маска может определяться 4 цифрами, но первую можно опустить, т.к. она не используется:
$ umask 002
$ umask
0002
Команда umask работает с цифрами справа налево, поэтому незначащие нули можно тоже опустить, по необходимости:
$ umask 77
$ umask
0077
Маску можно задать и с помощью более традиционных обозначений:
$ umask u=rwx,g=rwx,o=
В таком формате оно, как пишется, так и понимается - работает по принципу chmod.
Мы не исключаем "rwx" для пользователя и группы, а чистим все права для "остальных" персон. Такая запись равна маске "007":
$ umask
0007
$ touch filetest
$ ls -l
-rw-rw---- ... filetest
Группы прав также можно объединять:
$ umask ug=rwx,o=rx
Или же задавать сразу для всех категорий, использовав "a" (all):
$ umask a=rwx
Также можно работать с отдельными правами. Оператором "+" или "-" можно разрешить или запретить целевое действие:
$ umask -S ug-w
u=rx,g=rx,o=rx
$ umask -S a+w
u=rwx,g=rwx,o=rwx
Можно и комбинировать два предыдущих способа. Например, разрешить пользователю все операции, а группе и остальным убрать право на чтение:
$ umask u=rwx,go-r
LinuxCamp | #utils
./live/filesystem.squashfs
И если мы "разожмем" ее через:
$ unsquashfs filesystem.squashfs
То увидим внутри что-то очень знакомое:
bin etc initrd.img lib media opt
...
Именно тут-то и сидели те самые бинари, которые изначально требовалось подменить. Дальше пазл примерно сложился, я обратно собрал всю эту иерархию в ".squashfs":
$ mksquashfs squashfs-root filesystem.squashfs
После упаковал новый iso образ, отладил багу и проработал фикс. На всякий, сразу приложу команду, которой готовил образы:
$ sudo mkisofs -o ~/Загрузки/new.iso -quiet -R -b boot/grub/bios.img -no-emul-boot -boot-load-size 4 -boot-info-table ./
В общем, вот такой интересный опыт был получен. Как вы, вообще, хотите больше поговорить о файловых системах, внутрянке iso образов, grub?
LinuxCamp | #story
$ cp ./src/file ./dest/
2) без сохранения - с указанием нового имени файла;
$ cp ./src/file ./dest/file_backup
Сразу же скину ссылку на полную информацию о команде. Далее мы рассмотрим основные кейсы.
Копирование каталога
Для копирования каталогов нужно использовать опцию "-r":
$ cp -r source destination
$ ls destination
source
Тут ме переносим весь каталог вместе с его наполнением.
Если нет полной уверенности в том, что каталог "dest" существует, можно добавить флаг "-t" для вывода предупреждения:
$ cp -rt src dest3
cp: cannot stat 'dest3': No such file or directory
Копирование в этом случае выполнено не будет и каталог не будет создан.
Копирование содержимого каталога
Для того, чтобы перенести только содержимое директории, а не ее саму, используем:
$ cp -r src no_dest
$ ls no_dest
file1 file2 file3
Но есть нюансик... Это так работает только, если no_dest ранее не существовал. Если каталог назначения существует, то в нем будет создан src.
Для того чтобы избежать такого поведения можно использовать опцию "-T":
$ cp -rT src yes_dest
ls yes_dest
file1 file2 file3
Как вариант, еще можно решить задачу использованием шаблона поиска:
$ cp src/* dest
Однако в этом случае скрытые файлы скопированы не будут. Ну и это не проблема особо:
$ cp src/* src/.* dest
Обработка существующих файлов
По умолчанию, если файл каталоге назначения уже существует, он будет перезаписан. Если вы хотите, чтобы утилита спросила вас, стоит ли его перезаписывать, используйте флаг "-i":
$ cp -i src/* dest
cp: overwrite 'dest/file1'? y
cp: overwrite 'dest/file2'? y
С помощью опции "-n" можно отключить перезапись существующих ресурсов:
$ cp -n file1 dest
Создание бэкапов
Для существующих файлов можно cделать резервную копию с помощью опции "-b". Если использовать этот флаг, то в конце названия файла резервной копии будет добавлен символ тильды "~":
$ cp -b file1 dest
$ ls dest
file1~
При использовании параметра "--backup" можно настроить имя резервной копии. Вот доступные варианты:
1) none - резервная копия не делается;
2) numbered - к имени файла будет добавляться номер;
3) simple - в конец файла будет добавлен знак "~";
4) existing - если в целевой директории уже есть бэкапы, то будет использоваться аналогичный им тип нейминга;
Чтобы использовать номер в имени бэкапа используйте:
$ cp --backup=numbered file1 dest
$ ls dest
file1.~1~
Ещё один вариант обработки существующих файлов - заменять только, если изначальный новее.
Для этого нужно использовать опцию "-u":
$ cp -u file1 dest
Копирование ссылок
По умолчанию жесткие и символические ссылки копируются как обычные файлы, сохраняя содержимое ресурса, к которому были подвязаны:
$ cp test_link links
$ ls -l links
-rw-rw-r-- 1 ... test_link
Если вы хотите, чтобы символические ссылки копировались, сохраняя свой тип, нужно использовать опцию "-P":
$ cp test_link links
$ ls -l links
lrwxrwxrwx 1 ... test2_link -> test2
Ток, пожалуйста, не забывайте проверять путь к оригиналу на корректность - в примере выше ссылка поломана.
Для жестких ссылок существует другой подход. Если вы хотите, чтобы она осталась собой после копирования, нужно использовать опцию "-l":
$ cp -l hlink hlink1
$ ls -l
-rw-rw-r-- 3 ... file
-rw-rw-r-- 3 ... hlink
-rw-rw-r-- 3 ... hlink1
Сохранение атрибутов
По умолчанию cp обновляет временные метки и атрибуты прав доступа файлов при копировании.
Иногда может возникнуть необходимость их сохранить. Для этого используем "--preserve":
$ cp --preserve=all file dest
LinuxCamp | #utils
find каталог параметры действие
Параметры - дополнительные опции, например, глубина поиска, фильтр по имени и т.д;
Действие - что будет выполнено с результатами поиска;
По синтаксису выше найдем пустые каталоги в tmp:
$ find /tmp -type d -empty -print
Детально ознакомиться с параметрами и прочей петрушкой можете по ссылке.
Поиск по типу файла
Флаг "-type" позволяет искать файлы по типу, среди которых:
1) f – простые файлы;
2) d – каталоги;
3) l – символические ссылки;
4) b – блочные устройства (dev);
5) c – символьные устройства (dev);
6) p – именованные каналы;
7) s – сокеты;
Перечисляем только каталоги:
$ find . -type d
.
./.ssh
./.cache
Поиск по размеру файла
Флаг "-size" позволяет произвести фильтрацию по размеру.
Выведем все файлы более 1 Гб (+1G):
$ find . -size +1G
./android-studio-ide-183.5692245-mac.dmg
"+" — поиск файлов больше заданного размера;
"-" — поиск файлов меньше заданного размера;
Отсутствие знака — поиск по полному совпадению с заданным размером;
Единицы измерения файлов: c (байт), k (Кбайт), M (Мбайт), G (Гбайт).
Поиск пустых файлов и каталогов
Параметр "-empty" позволяет найти пустые ресурсы:
$ find . -type d -empty
./datafiles
Не учитывать регистр при поиске
Если опция "-name" чувствительна к регистру, то "-iname" наоборот:
$ find . -name "new*"
./new test file
./newFile
$ find . -iname "new*"
./NewFile
./new test file
./newFile
Несколько каталогов
Для поиска по нескольким каталогам просто используем перечисление:
find ./dir1 ./dir2 -type f -name "*.c"
Поиск по правам доступа
Команда нам позволяет искать ресурсы по определенной маске прав, например, 0664:
$ find . -type f -perm 0664
Вместо числового представления маски можно использовать символьное для: u (user) g (group) и o (other).
Выполним поиск файлов доступных владельцу для чтения/записи:
$ find /etc -perm /u=rw
Чтобы немного въехать в суть прав доступа, можно просмотреть вот этот пост.
Ограничение глубины поиска
Если нам нужно указать максимальную глубину поиска, используем "-maxdepth".
Следующий запуск find пройдется только по самому верхнему уровню указанного каталога:
$ find /etc -maxdepth 1
Операторы
Для инвертирования шаблона либо объединения можно применять операторы: and, or, not.
Флаг "-and" обычно можно опустить, т.к. он ставится по дефолту.
Найдем файлы, которые не соответствуют шаблону:
$ find . -not -name "test*"
Либо найдем все файлы, начинающиеся на "test", но без расширения "php":
$ find . -name "test" -not -name "*.php"
Можем также объединить несколько условий и найти ресурсы, которые принадлежат "xoadmin" и имеют размер "< 100 байт":
$ find . -user xoadmin -and -size -100c -type f
Если нужно учесть принадлежность к еще какому-нибудь пользователю, используем "or":
$ find . \( -user xoadmin -or -user vasya \) -and -size -100c -type f
Действия
К команде можно добавить действия, которые будут выполнены с результатами поиска:
1) -delete: удаляет результаты поиска;
$ find . -empty -delete
2) -ls: выводит доп информацию;
3) -print: показывает полный путь к найденным файлам (стоит по умолчанию);
4) -exec: выполняет указанную команду для найденных ресурсов;
$ find . -empty -exec rm -rf {} +
Тут мы удаляем все пустые файлы и каталоги одним вызовом "rm -rf".
Можем через exec найти файлы и прочитать их:
$ find . -type f -exec cat {} \;
Вместо {} подставляется путь к файлу. Если команда оканчивается на "\;", значит она будет выполнена для каждой строки с результатом.
LinuxCamp | #utils
$ head test
Line 1
Line 2
Line 3
...
$ ls | head
adduser.conf
alsa
alternatives
...
Если в команде head не указаны флаги, то по умолчанию выводятся первые 10 строк.
Для того, чтобы ограничить вывод и просмотреть N элементов, используем параметр "-n":
$ head -n2 test
Line 1
Line 2
Параметр "-n" также можно использовать для того, чтобы вывести все содержимое, за исключением N последних строк. Для этого нужно использовать выражение вида "-n-N".
Если у нас всего 10 строк и требуется получить первые 3, сделаем:
$ head -n-7 test
Line 1
Line 2
Line 3
Без проблем можно единовременно получить вывод с нескольких файлов. Достаточно перечислить названия через пробел:
$ head -n2 test test2
==> test <==
Line 1
Line 2
==> test2 <==
Line 11
Line 12
Если вывод названий файлов и разделителей "\n" нам не нужен, используем флаг "-q":
$ head -n2 -q test test2
Line 1
Line 2
Line 11
Line 12
Команда tail печатает последние строки файла — по умолчанию также 10:
$ tail test
Line 1
Line 2
Line 3
...
Принцип использования команды tail практически аналогичен head. Если хотим ограничить вывод последними 3 строками, добавляем флаг "-n":
$ tail -n3 test
Line 8
Line 9
Line 10
Если поставить перед номером знак "+", печать начнется со строки этого номера и продолжится до конца файла:
$ tail -n+9 test
Line 9
Line 10
Обе команды вместе
Объединяйте head и tail, чтобы напечатать любой диапазон строк.
Например, чтобы вывести строки c 4 по 7, используем head для элементов "1-7" и tail для "7-4":
$ head -n7 test | tail -n4
Line 4
Line 5
Line 6
Line 7
В общем, чтобы отобразить строки от M до N, извлеките первые N строк с помощью head, затем выведите последние N-M+1 строк с помощью tail.
Чуток жизненной практики
Последнее время частенько приходится работать с патчами - накладывать их на приложения через quilt и снимать.
Нужно было наложить на утилиту только 10 патчей из 20. Для того, чтобы поработать с диапазоном, использовал команду head:
$ quilt series | head -n 10 | xargs -L1 quilt push
1) quilt series выводит список патчей в столбец;
2) head -n 10 отображает только первые 10 строк;
3) xargs -L1 quilt push выполняет команду для каждого отдельного патча;
LinuxCamp | #utils
$ ls
'test script.sh' test test_1 test_2
$ ls | grep -w test
test script.sh
test
Аналогичного результата можно добиться через регулярное выражение:
$ ls | grep "\<test\>"
test script.sh
test
"\<" — начало слова.
"test" — искомый текст.
"\>" — конец слова.
Угловые скобки должны экранироваться, иначе они будут интерпретироваться как простые символы.
Игнорировать регистр
По умолчанию, grep чувствительна к регистру, что немного мешает поиску. Проблема решается путем добавления ключа "-i" к команде:
ls | grep -i new
newFile
NewFile
Вывод файлов с совпадениями
Используйте параметр "-l", чтобы вывести не сами строки, а только пути к файлам, в которых они содержатся:
$ grep -r -l "libnma" /usr/share
/usr/share/doc/libnma-gtk4-0/copyright
Параметр "-r" отвечает за рекурсивный поиск - grep прошерстит не только 1 уровень каталога, а пойдет вглубь.
Поиск по нескольким параметрам
Для того, чтобы передать команде несколько вводных данных для определения совпадений, используется флаг "-e" перед каждым объектом поиска:
$ ls | grep -i -e new -e old
NewFile
newFile
oldFile
Эту команду система понимает, как "или-или" и выводит все вхождения указанных слов.
Использование регулярных выражений
Настоящая сила grep проявляется, когда вы переходите от сопоставления простых строк к сопоставлению шаблонов - регулярных выражений.
Выражения бывают 2 типов: basic и extended. Одна из особенностей второго типа заключается в том, что некоторые символы требуют экранирования для сохранности фич: ?, +, {, |, (, ), <, >.
Но можно обойтись просто добавлением флага "-E":
$ ls | grep -E "script|test"
1. Квадратные скобки "[]" используются, чтобы провести проверку на соответствие одному из указанных символов:
$ ls | grep "test[23]"
test2
test3
Можем указать "-" для того, чтобы использовать диапазон значений:
$ ls | grep "test[1-3]"
test2
test3
2. Каретка "^" используется для поиска строк, которые начинаются с указанного шаблона. Давайте найдем совпадение всех строк, начинающихся с заглавной буквы:
$ grep "^[A-Z]" myfile
A lot of text
Hello world
3. Знак доллара "$" означает конец строки. В результат входят только те элементы, конец которых подходит под шаблон:
$ grep "world$" myfile
Hello world
hello world
4. Точка "." обозначает любой одиночный символ, кроме новой строки. Регулярное выражение "....." обозначает любую строку, содержащую минимум 5 символов:
$ grep '.....' myfile
5. Вертикальная черта "|" выполняет роль логического оператора "ИЛИ":
$ ls | grep "script\|test"
script
test
В общем, регулярные выражения прекрасны и многообразны. Детальнее ознакомиться с ними можете по ссылке.
Экранирование
Иногда выражения приводят к неожиданным результатам.
Предположим, вы хотите найти в файле "myfile" только те строки, которые заканчиваются на ".sh".
Следующая команда выдаст неверный результат, поскольку точка — это регулярное выражение, означающее «любой символ»:
$ grep ".sh" myfile
script_name.sh
script_namesh
Чтобы обойти эту проблему, требуется экранировать спецсимвол:
$ grep "\.sh" myfile
script_name.sh
Такое решение иногда становится громоздким. К счастью, можно заставить grep забыть о регулярных выражениях и искать буквально то, что мы указываем.
Для этого используется параметр (fixed) "-F":
$ grep -F ".sh" myfile
script_name.sh
LinuxCamp | #utils