Понимать сложную замену команд с помощью {} и нескольких `\ls`

Понимать сложную замену команд с помощью {} и нескольких `\ls`

Я пытаюсь понять эту строку из скрипта оболочки. Я знаю, что это $(..)означает запустить ..и вставить его вывод туда, где вы найдете $()в операторе. Но что происходит между этими скобками? Что делает \lsи как это связано с \в предыдущих строках? Это \\разделение на две строки? Это \lsто же самое, что и обычное ls?

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

решение1

Вывод трех lsкоманд передается команде paste, которая объединяет их в значение:

$VOLTDB_VOLTDB"/voltdb-*.jar:$VOLTDB_LIB"/*.jar:$VOLTDB_LIB"/extension/*.jar

ПРИМЕЧАНИЕ:Переменные $VOLTDB_VOLTDBи $VOLTDB_LIBбудут расширены, и для каждой из этих команд может быть больше значений, чем просто один файл ls. Видите *там? Это символ glob, который действует как подстановочный знак и расширяется до чего угодно между левой стороной (voltdb-) и правой стороной (.jar), например.

Они будут соответствовать:

voltdb-1.jar
voltdb-blah.jar
voltdb-12345.jar

Затем все включается в переменную APPCLASSPATH:

APPCLASSPATH=$CLASSPATH:$VOLTDB_VOLTDB"/voltdb....etc.

Команда вставки

Вот пример, в котором я использую seqкоманду для генерации последовательности чисел от 1 до 10.

$ seq 10 | paste -sd ':' -
1:2:3:4:5:6:7:8:9:10

Вы можете видеть, что pasteкоманда объединяет выходные данные и разделяет их двоеточием ( :).

Вы также можете повторить команду примера следующим образом:

$ { echo "hi1"; echo "hi2"; echo "hi3"; } | paste -sd ':' -
hi1:hi2:hi3

ПРИМЕЧАНИЕ:Команда -вставки указывает, что необходимо взять входные данные из STDIN и вывести каждый аргумент по мере их поступления, разделив его точкой :.

Используя различные переключатели, pasteможно также разбить данные на группы в зависимости от количества -символов «'» после них.

Вставить примеры

Вот пример с 2 --мя.

$ seq 10 | paste - -
1       2
3       4
5       6
7       8
9       10

Вот 3 -.

$ seq 10 | paste - - -
1       2       3
4       5       6
7       8       9
10

Итак, он сообщает paste, сколько аргументов pasteдолжно быть напечатано в каждой строке. Но не путайтесь, пример, с которым вы имеете дело, просто берет входные данные из STDIN, разделяет каждый аргумент пробелами и печатает его с последующим :. При указании нескольких -' вы указываете pasteбрать аргументы, 2 и по одному, 3 за раз и т. д.

Аргументы по 2 за раз, разделенные :точкой:

$ seq 10 | paste -d ':' - -
1:2
3:4
5:6
7:8
9:10

$ seq 10 | paste -d ':' - - -
1:2:3
4:5:6
7:8:9
10::

Кстати, если вы включаете переключатель, -sвы говорите, pasteчто нужно принимать аргументы последовательно (серийно). Посмотрите, что происходит, когда вы используете его в одном из примеров выше.

2 за раз:

$ seq 10 | paste -sd ':' - -
1:2:3:4:5:6:7:8:9:10

3 за раз:

$ seq 10 | paste -sd ':' - - -
1:2:3:4:5:6:7:8:9:10

решение2

$(command)выполняет команду и подставляет ее вывод.

{ list; }— это групповая команда, выполняющая несколько команд в текущей среде оболочки. Она похожа на (list), но не создает подоболочку.

\commandиспользуется для игнорирования псевдонимов команд, которые могут существенно изменить ожидаемое поведение команд.

В \конце строки просто означает, что эта строка продолжается, поэтому оболочка будет видеть следующую строку как часть текущей. Обычно не требуется, когда это очевидно из контекста (открывающая скобка или кавычка).

решение3

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

\lsпохож на ls, за исключением того, что если lsэто псевдоним, обратная косая черта предотвращает расширение псевдонима. Это гарантирует, что lsиспользуется команда, а не какой-либо псевдоним, который может добавить нежелательный вывод, такой как суффикс классификатора ( -F).

Команды ls, вызываемые с существующими именами файлов в качестве аргументов, перечисляют свои аргументы, по одному на строку. Параметр -1не имеет эффекта, поскольку вывод lsотправляется в канал, а не на терминал. Если lsполучает аргумент, который не является именем существующего файла, он ничего не отображает в своем стандартном выводе и вместо этого отображает ошибку. Ошибки от lsкоманд перенаправляются в никуда с помощью 2> /dev/null. Есть две причины, по которым lsможет получить аргумент, который не является файлом: если одна из переменных не ссылается на существующий читаемый каталог или если нет файла, соответствующего шаблону подстановочных знаков. В любом случае шаблон передается неразвернутым в ls.

Обратные косые черты в конце строк заставляют оболочку игнорировать следующую новую строку. Ни одна из них здесь не полезна, поскольку в каждой точке, где они используются, оболочка ожидает необязательную новую строку.

Скобки { … } группируют команды. Составная команда { \ls …; \ls …; \ls … ; }передается по конвейеру pasteи ее ошибки перенаправляются в /dev/null.

Команда pasteобъединяет все входные строки с a :между ними. Это эквивалентно , за tr '\n' :исключением того, что a не ставится :в конце.

Подстановка команды приводит к интерполяции $(…)выходных данных в , после значения переменной с двоеточием для разделения двух частей.pasteAPPCLASSPATHCLASSPATH

Вот упрощенная версия. Она немного отличается от оригинала тем, что если ни один из шаблонов подстановочных знаков не соответствует ничему, то APPCLASSPATHбудет равно CLASSPATHбез дополнительного двоеточия в конце (что, вероятно, желательно).

APPCLASSPATH=$CLASSPATH:$(
  \ls "$VOLTDB_VOLTDB"/voltdb-*.jar "$VOLTDB_LIB"/*.jar "$VOLTDB_LIB"/extension/*.jar |
  tr '\n' :) 2>/dev/null
APPCLASSPATH=${APPCLASSPATH%:}

Связанный контент