Подстановка вывода команды:
$()Оператор, который мы сегодня рассмотрим является супер полезной фичей оболочки. Мы буквально можем подставить вывод команды либо целой цепочки посреди выражения.
Предположим, у вас есть несколько тысяч текстовых файлов c песнями. Каждый файл содержит название песни, ее текст и имя исполнителя:
Название: Зеркала
Исполнитель: Лепс
Острые углы, нервы, суета
Стоит задача распределить файлы в подкаталоги по исполнителям. Ну, для начала, можно найти все файлы песен исполнителя с помощью
grep:
$ grep -l "Лепс" *.txt
song1.txt
song2.txt
Затем переместить каждый файл в необходимый каталог:
$ mkdir leps
$ mv song1.txt leps
$ mv song2.txt leps
Чет неудобно, так? Было бы неплохо сказать оболочке: «Перемести все файлы, содержащие строку Лепс, в каталог
leps».
Для этого нужно забрать то, что нам выдала команда "
grep -l" и передать результат в качестве списка аргументов для
mv:
$ mv $(grep -l "Лепс" *.txt) leps
Синтаксис "
$(команда)" выполняет выражение в круглых скобках и заменяет вставку его выводом.
Таким образом, "
grep -l" подменяется, подходящими под условие именнами файлов. Результат использования
$() в примере выше аналогичен:
$ mv song1.txt song2.txt leps
В сценариях оболочки подстановка бывает полезна для сохранения вывода команды в переменной:
переменная=$(команда)
Например, напишем простенький скрипт, который поможет нам узнать, содержит ли текущая директория файлы:
status=$(ls ./ 2>/dev/null | wc -l)
if [ "$status" -gt 0 ]; then
echo "В директории есть $status файлов"
else
echo "Директория пуста или не существует"
fi
Выдаем права на выполнение, запускаем и проверяем:
$ chmod +x script.sh
$ ./script.sh
В директории есть 66 файлов
Для чего бывает полезно брать "$()" в кавычки?Есть несколько основных кейсов, когда следует использовать
"$()" вместо
$().
Во-первых, если вывод команды содержит пробелы, он будет разбит на отдельные слова.
Представим, что стоит задача определить для текущей директории специальные права.
Есть момент - имя каталога состоит из нескольких слов, разделенных пробелами "
photo and video":
$ pwd
$ /home/xoadmin/photo and video
$ chmod 777 $(pwd)
После подстановки оболочка интерпретирует это как попытку применить
chmod к трём разным объектам: "
/home/xoadmin/photo", "
and", и "
video". Это, вероятно, приведёт к ошибке:
chmod: cannot access '/home/xoadmin/photo': No such file or directory
chmod: cannot access 'and': No such file or directory
chmod: cannot access 'video': No such file or directory
Чтобы вывод
pwd воспринимался, как единое целое, следует заключить оператор в кавычки:
$ chmod 777 "$(pwd)"
Во-вторых, без кавычек, символы перевода строки могут быть удалены при выводе через
echo:
$ echo $(ls)
adduser.conf alsa alternatives apache2 apg.conf apparmor
Если требуется сохранить четкую структуру текста, содержащего спец символы, следует использовать "
$()":
$ echo "$(ls)"
adduser.conf
alsa
alternatives
🐧 LinuxCamp