У меня есть сложная команда, из которой я хотел бы сделать скрипт shell / bash. Я могу написать это с точки зрения $1
легко:
foo $1 args -o $1.ext
Я хочу иметь возможность передать несколько входных имен в сценарий. Какой правильный способ сделать это?
И, конечно же, я хочу обрабатывать имена файлов с пробелами в них.
bash
command-line
Телема
источник
источник
Ответы:
Используйте
"$@"
для представления всех аргументов:Это будет перебирать каждый аргумент и выводить его на отдельной строке. $ @ ведет себя как $ * за исключением того, что при кавычках аргументы корректно разбиваются, если в них есть пробелы:
источник
"$@"
является то, что он расширяется до нуля, когда нет позиционных параметров, тогда как"$*"
расширяется до пустой строки - и да, есть разница между отсутствием аргументов и одним пустым аргументом. Смотрите${1:+"$@"} in
/ bin / sh` .$var
я смог выполнить аргументы.shift
выбрасывает$1
и сдвигает все последующие элементы.Переписать из теперь удален ответ по VonC .
Сжатый ответ Роберта Гэмбла касается непосредственно вопроса. Это усиливает некоторые проблемы с именами файлов, содержащими пробелы.
Смотрите также: $ {1: + "$ @"} в / bin / sh
Основной тезис:
"$@"
правильно и$*
(без кавычек) почти всегда неправильно. Это потому, что"$@"
работает нормально, когда аргументы содержат пробелы, и работает так же, как и$*
когда их нет. В некоторых случаях"$*"
это тоже нормально, но"$@"
обычно (но не всегда) работает в одних и тех же местах. Без кавычек$@
и$*
эквивалентны (и почти всегда неверны).Итак, в чем разница между
$*
,$@
,"$*"
и"$@"
? Все они связаны со «всеми аргументами оболочки», но делают разные вещи. Когда без кавычек,$*
и$@
делать то же самое. Они рассматривают каждое «слово» (последовательность без пробелов) как отдельный аргумент. Однако формы в кавычках совершенно разные:"$*"
обрабатывает список аргументов как одну строку, разделенную пробелами, тогда"$@"
как аргументы обрабатывают почти точно так, как они были указаны в командной строке."$@"
вообще ничего не расширяется, когда нет позиционных аргументов;"$*"
расширяется до пустой строки - и да, есть разница, хотя это может быть трудно воспринимать. См. Дополнительную информацию ниже, после введения (нестандартной) командыal
.Вторичный тезис: если вам нужно обработать аргументы с пробелами, а затем передать их другим командам, вам иногда требуются нестандартные инструменты для помощи. (Или вы должны использовать массивы осторожно:
"${array[@]}"
ведет себя аналогично"$@"
.)Пример:
Почему это не работает? Это не работает, потому что оболочка обрабатывает кавычки, прежде чем она расширяет переменные. Итак, чтобы оболочка обратила внимание на кавычки
$var
, вы должны использоватьeval
:Это действительно сложно, когда у вас есть имена файлов, такие как "
He said, "Don't do this!"
" (с кавычками и двойными кавычками и пробелами).Оболочки (все они) не облегчают работу с такими вещами, поэтому (как ни странно) многие программы Unix не справляются с ними. В Unix имя файла (один компонент) может содержать любые символы, кроме косой черты и NUL
'\0'
. Тем не менее, оболочки настоятельно рекомендуют не использовать пробелы, символы новой строки или табуляции нигде в именах путей. Именно поэтому стандартные имена файлов Unix не содержат пробелов и т. Д.При работе с именами файлов, которые могут содержать пробелы и другие неприятные символы, вы должны быть чрезвычайно осторожны, и я давно обнаружил, что мне нужна программа, которая не является стандартной для Unix. Я называю это
escape
(версия 1.1 датирована 1989-08-23T16: 01: 45Z).Вот пример
escape
использования - с системой управления SCCS. Это сценарий обложки, который выполняет какdelta
(думайте о регистрации ), так иget
(думайте о регистрации ). Различные аргументы, особенно-y
(причина, по которой вы внесли изменения) будут содержать пробелы и переводы строк. Обратите внимание, что сценарий датируется 1992 годом, поэтому он использует обратные тики вместо$(cmd ...)
обозначений и не использует их#!/bin/sh
в первой строке.(Я бы, вероятно, не использовал escape сейчас так тщательно -
-e
например, в аргументе это не нужно - но в целом, это один из моих более простых сценариев, использующихescape
.)escape
Программа просто выводит свои аргументы, а какecho
делает, но он гарантирует , что аргументы защищены для использования сeval
(один уровеньeval
, у меня есть программа , которая сделала удаленное выполнение оболочки, и что необходимо , чтобы избежать выводаescape
).У меня есть другая программа,
al
которая называет свои аргументы по одному на строку (и она еще более древняя: версия 1.1 от 1987-01-27T14: 35: 49). Это наиболее полезно при отладке сценариев, поскольку его можно подключить к командной строке, чтобы увидеть, какие аргументы фактически передаются команде.[ Добавлено: А теперь, чтобы показать разницу между различными
"$@"
обозначениями, вот еще один пример:Обратите внимание, что ничего не сохраняет оригинальные пробелы между
*
и*/*
в командной строке. Также обратите внимание, что вы можете изменить «аргументы командной строки» в оболочке, используя:Это устанавливает 4 опции, '
-new
', '-opt
', 'and
' и 'arg with space
'.]
Хм, это довольно длинный ответ - возможно, толкование - лучший термин. Исходный код
escape
доступен по запросу (электронная почта на имя, точка, фамилия на gmail, точка com). Исходный кодal
невероятно прост:Это все. Он эквивалентен
test.sh
сценарию, который показал Роберт Гэмбл, и может быть написан как функция оболочки (но функции оболочки не существовали в локальной версии оболочки Bourne, когда я впервые писалal
).Также обратите внимание, что вы можете написать
al
в виде простого сценария оболочки:Условное условие необходимо для того, чтобы оно не выдавало выходных данных при отсутствии аргументов. Команда
printf
выдаст пустую строку только с аргументом строки формата, но программа на Си ничего не выдаст.источник
Обратите внимание, что ответ Роберта верен, и он
sh
тоже работает. Вы можете (переносимо) упростить это еще больше:эквивалентно:
Т.е. тебе ничего не нужно!
Тестирование (
$
это командная строка):Я впервые прочитал об этом в среде программирования Unix Kernighan и Pike.
В
bash
,help for
документы это:источник
"$@"
означает загадочное , и как только вы узнаете, что этоfor i
значит, оно не менее читабельно, чемfor i in "$@"
.for i
лучше, потому что это экономит нажатия клавиш. Я сравнил удобочитаемостьfor i
иfor i in "$@"
.Для простых случаев вы также можете использовать
shift
. Он обрабатывает список аргументов как очередь. Каждыйshift
выбрасывает первый аргумент, и индекс каждого из оставшихся аргументов уменьшается.источник
shift
в цикле for, этот элемент все еще является частью массива, тогда как с этимshift
работает как ожидалось.echo "$1"
чтобы сохранить интервал в значении строки аргумента. Кроме того, (незначительная проблема) это разрушительно: вы не можете повторно использовать аргументы, если вы удалили их все. Часто это не проблема - вы все равно обрабатываете список аргументов только один раз.--file myfile.txt
Итак, $ 1 - это параметр, $ 2 - это значение, и вы дважды вызываете shift, когда вам нужно пропустить другой аргументВы также можете обращаться к ним как к элементам массива, например, если вы не хотите перебирать их все
источник
./my-script.sh param1 "param2 is a quoted param"
: - используя argv = ($ @), вы получите [param1, param2], - используя argv = ("$ @"), вы получите [param1, param2 - это цитируемый параметр]источник
[ $# != 0 ]
это лучше. Выше#$
должно быть$#
какwhile [[ $# > 0 ]] ...
Усиление ответа baz: если вам нужно перечислить список аргументов с индексом (например, для поиска определенного слова), вы можете сделать это, не копируя список или не изменяя его.
Допустим, вы хотите разделить список аргументов по двойному тире («-») и передать аргументы перед тире одной команде, а аргументы после тире другой:
Результаты должны выглядеть так:
источник
getopt Используйте команду в ваших сценариях для форматирования любых параметров или параметров командной строки.
источник