Добавьте аргументы в 'bash -c'

22

Допустим, я хочу запустить команду через Bash следующим образом:

/bin/bash -c "ls -l"

Согласно странице руководства Bash, я мог бы запустить ее так:

#               don't process arguments after this one
#               |   pass all unprocessed arguments to command
#               |   |
#               V   V
/bin/bash -c ls -- -l

за исключением того, что, кажется, не работает (кажется, игнорируется). Я делаю что-то не так или неправильно интерпретирую man-страницу?

Соответствующие цитаты из человека:

Если указана опция -c, то команды читаются из строки. Если после строки есть аргументы, они присваиваются позиционным параметрам, начиная с $ 0.

а также

A - сигнализирует об окончании опций и отключает дальнейшую обработку опций. Любые аргументы после - обрабатываются как имена файлов и аргументы.

Слартибартфаст
источник

Ответы:

33

Вы неправильно интерпретируете справочную страницу. Во-первых, часть о том, как --сигнализировать об окончании опций, не имеет отношения к тому, что вы пытаетесь сделать. С этого -cмомента переопределяет остальную часть командной строки, так что она больше не проходит обработку опций bash, то есть, --она будет передана команде, а не bash как маркер конца опций.

Вторая ошибка заключается в том, что дополнительные аргументы присваиваются в качестве позиционных параметров запущенному процессу оболочки, а не передаются в качестве аргументов команды. Итак, то, что вы пытаетесь сделать, можно сделать одним из следующих способов:

/bin/bash -c 'echo "$0" "$1"' foo bar
/bin/bash -c 'echo "$@"' bash foo bar

В первом случае передаются эхо-параметры $0и $1явно, а во втором случае используется "$@"расширение как обычно, как «все позиционные параметры, кроме $ 0». Обратите внимание, что в этом случае мы также должны передать что-то для использования $0; Я выбрал «bash», так как это то, $0что обычно будет, но все остальное будет работать.

Что касается причины , это делается таким образом, вместо того , чтобы просто передавая любые аргументы , которые вы даете непосредственно к команде вы перечисляете: обратите внимание , что документация говорит «команда s считывается из строки», во множественном числе. Другими словами, эта схема позволяет вам:

/bin/bash -c 'mkdir "$1"; cd "$1"; touch "$2"' bash dir file

Но, обратите внимание , что лучший способ , чтобы удовлетворить ваши первоначальной цели может быть использовать envвместо bash:

/usr/bin/env -- "ls" "-l"

Если вам не нужны какие-либо функции, предоставляемые оболочкой, нет причин использовать ее - использование envв этом случае будет быстрее, проще и меньше набирает текст. И вам не нужно думать так усердно, чтобы убедиться, что он будет безопасно обрабатывать имена файлов, содержащие метасимволы оболочки или пробелы.

godlygeek
источник
3

Я не уверен, какова ваша цель, но если вы просто пытаетесь создать машину Рубе Голдберга - «устройство, изобретение, устройство или аппарат, которые намеренно перерабатываются или перестараются, чтобы выполнить очень простую задачу в очень сложная мода »- тогда попробуй

sh -c 'ls $0' -l

или

sh -c 'ls $1' supercalifragilisticexpialidocious -l

или даже

sh -c 'ls -$0' l

Вы должны быть в состоянии понять, как они работают, из ответа Godlygeek.

Скотт
источник