리눅스 명령행 인자: 명령어 옵션과 따옴표, 옵션 끝 표시, $1, $# 받기
Аргументы командной строки Linux (command-line argument) — это значения, которые передают программе, записывая их после имени команды через пробел. Мы передали опции, кавычки, подстановочные знаки и -- тестовому скрипту на сервере AlmaLinux 9, который выводит полученные аргументы как есть: аргументы разделяла оболочка, а опции читала каждая команда сама.
Вывод ниже — это ровно то, что получилось при запуске в bash 5.1 под учётной записью root на сервере AlmaLinux 9.8. Тестовые скрипты и файлы-примеры созданы в отдельной рабочей папке, а путь /home/user/www — пример значения.
1️⃣ Что такое аргументы командной строки Linux?
Если написать в командной строке что-то вроде [команда арг1 арг2], оболочка разделит слова по пробелам. Первое слово станет запускаемой программой, а остальные по порядку передаются ей как аргументы.
Чтобы увидеть переданные аргументы, мы создали в рабочей папке args.sh. В $0 хранится имя, под которым его запустили, в $# — количество аргументов, а начиная с $1 — сами аргументы по порядку. Квадратные скобки добавлены, чтобы было видно, где каждый аргумент начинается и заканчивается.
#!/bin/bash
echo "\$0 = $0"
echo "\$# = $#"
i=1
for a in "$@"; do
echo "\$$i = [$a]"
i=$((i+1))
doneМы дали скрипту право на выполнение и запустили его с тремя словами: a, b и c.
./args.sh a b c$0 = ./args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]Три слова попали в $1, $2 и $3, а $# было равно 3. Если запустить скрипт, написав его имя после bash, в $0 окажется имя ровно в том виде, как его написали, — args.sh.
bash args.sh a b c$0 = args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]Изменилось только $0 — на args.sh; три аргумента и их количество остались такими же, как раньше.
2️⃣ Аргументы командной строки и опции команд
Команды Linux обычно пишут в порядке [команда -опция аргумент]. Опции меняют поведение команды, а аргументы задают файлы, пути или значения, с которыми она работает.
ls -l /home/user/wwwДля оболочки -l — тоже просто аргумент. Когда мы передали те же слова в args.sh, -l попал в $1, а путь — в $2.
./args.sh -l /home/user/www$0 = ./args.sh
$# = 2
$1 = [-l]
$2 = [/home/user/www]Читать -l как опцию — дело ls. Поэтому одна и та же буква в разных командах значит разное: -n у head задаёт число выводимых строк, а -n у ls выводит владельца номером вместо имени.
Некоторые опции берут слово сразу после себя как собственное значение. В команде find -type берёт f, а -name — "*.txt"; такое значение, привязанное к опции, называется аргументом опции.
find . -type f -name "*.txt"В этой команде начальная . — аргумент, не привязанный ни к одной опции; он задаёт папку, с которой начинается поиск.
3️⃣ Форматы опций команд Linux
Короткие опции начинаются с одного дефиса, состоят из одной буквы, и несколько из них можно писать слитно. Сначала мы вывели папку site из рабочей папки командой [ls -l -a].
ls -l -a sitetotal 8
drwxr-xr-x 3 root root 52 Oct 28 16:00 .
drwxr-xr-x 3 root root 137 Oct 29 01:20 ..
-rw-r--r-- 1 root root 17 Oct 28 16:00 .htaccess
drwxr-xr-x 2 root root 23 Oct 28 16:00 css
-rw-r--r-- 1 root root 14 Oct 28 16:00 index.htmlЗатем сравнили это через diff с выводом [ls -la], где две буквы написаны слитно.
diff <(ls -l -a site) <(ls -la site) && echo samesameДва вывода не различались ни на один символ. Длинные опции начинаются с двух дефисов и пишутся словами; --all у ls — та же опция, что и -a, поэтому [ls -l --all site] дал тот же результат.
Длинную опцию принимают, даже если написать только её начало, при условии что оно подходит к одной опции. --al подходило к двум опциям, --all и --almost-all, поэтому ls не вывел список и завершился с кодом выхода 2.
ls --al sitels: option '--al' is ambiguous; possibilities: '--all' '--almost-all'
Try 'ls --help' for more information.Опции со значением можно записывать по-разному. При выводе первых двух строк a.txt через head значение короткой опции можно приписать вплотную: [-n2].
head -n2 a.txtalpha
betaУ длинной опции значение присоединяют знаком равенства: [--lines=2].
head --lines=2 a.txtalpha
betaВсе четыре формы, включая [-n 2] и [--lines 2] через пробел, вывели две строки alpha и beta.
ls, head и cat читают опции функцией getopt_long из библиотеки C. Просмотр трёх файлов программ через strings показал, что в каждом есть имя этой функции.
Чтобы проверить те же правила в оболочке, используют команду getopt из util-linux. После -o пишут короткие опции, после -l — длинные; двоеточие после буквы означает, что опция принимает значение.
getopt -o lan: -l all,lines: -- -la -n 2 --all a.txt -l -a -n '2' --all -- 'a.txt'Слитное -la разделилось на -l и -a, а -n 2 объединилось в -n со значением 2. a.txt, которое не является опцией, перенесено в конец, после --.
4️⃣ Аргументы в кавычках и подстановочные знаки
Имя файла с пробелом нужно заключить в кавычки, чтобы оно передалось одним аргументом.
./args.sh "my file.txt" report.txt$0 = ./args.sh
$# = 2
$1 = [my file.txt]
$2 = [report.txt]Без кавычек my и file.txt разделились, и $# стало 3. Если так передать их ls или cat, команды будут искать два файла с именами my и file.txt.
./args.sh my file.txt report.txt$0 = ./args.sh
$# = 3
$1 = [my]
$2 = [file.txt]
$3 = [report.txt]Подстановочные знаки оболочка заменяет именами файлов ещё до того, как их получит программа. Когда мы передали *.txt в рабочей папке, туда попали четыре файла с окончанием .txt в порядке имён.
./args.sh *.txt$0 = ./args.sh
$# = 4
$1 = [a.txt]
$2 = [b.txt]
$3 = [my file.txt]
$4 = [report.txt]"*.txt" в кавычках оболочка не заменила, и он стал одним аргументом буква в букву. Для опций вроде -name у find, где программа сама сравнивает шаблон, его передают именно так, в кавычках.
./args.sh "*.txt"$0 = ./args.sh
$# = 1
$1 = [*.txt]Пустые кавычки тоже передаются как один пустой аргумент. При запуске [./args.sh '' b] $# было 2, а $1 — пустым.
5️⃣ Конец опций команды (--)
Аргумент, начинающийся с дефиса, например файл с именем -n, команда читает как опцию. Когда мы запустили [ls -n] в папке dash, где есть только этот файл, ls принял -n не за имя файла, а за опцию числового вывода и вывел содержимое папки.
ls -ntotal 4
-rw-r--r-- 1 0 0 10 Oct 28 16:00 -nАргументы, записанные после --, не читаются как опции, даже если начинаются с дефиса. [ls -- -n] вывел только имя файла -n.
ls -- -n-nДаже внутри одной команды одни и те же символы до и после -- читаются по-разному. Когда мы дважды передали -n команде cat, первое -n прочиталось как опция номеров строк, а -n после -- — как имя файла, и содержимое файла вышло с номерами строк.
cat -n -- -n 1 dash fileМожно также добавить путь и написать ./-n: тогда аргумент не начинается с дефиса и читается как тот же файл -n.
Считать -- концом опций — тоже правило на стороне команды. Когда мы передали его в args.sh, который опции не читает, -- попал в $1 без изменений.
./args.sh -- -a$0 = ./args.sh
$# = 2
$1 = [--]
$2 = [-a]Соглашения об утилитах POSIX устанавливают, что первое --, не являющееся аргументом опции, принимается как конец опций. Поэтому в командах, следующих этим соглашениям, имена файлов, начинающиеся с -, пишут после --.
6️⃣ Получение аргументов командной строки в скрипте оболочки
Скрипт оболочки читает полученные аргументы через позиционные и специальные параметры. Функция main(int argc, char *argv[]) программы на C получает те же аргументы; если поставить их рядом, получится так.
| Параметр | Содержащееся значение | Функция main в C |
|---|---|---|
| $0 | Имя запущенного скрипта | argv[0] |
| $1 ~ $9 | С первого по девятый аргумент | argv[1] ~ argv[9] |
| ${10} | Начиная с десятого аргумента — в фигурных скобках | argv[10] |
| $# | Количество аргументов, $0 не считается | argc - 1 |
| "$@" | Все аргументы, каждый отдельно | От argv[1] до конца |
| "$*" | Все аргументы, соединённые пробелами в один | — |
Программа на Python получает те же аргументы в виде списка sys.argv. Когда мы передали три аргумента через [python3 -c], взятый в кавычки my file.txt попал в один элемент списка, а в первом элементе оказался -c.
python3 -c 'import sys; print(sys.argv)' a "my file.txt" -l['-c', 'a', 'my file.txt', '-l']"$@" и "$*" дают разный результат, если заключить их в двойные кавычки. Чтобы увидеть разницу, мы создали star.sh, который выводит обе формы по очереди.
#!/bin/bash
echo 'with "$@"'
printf ' [%s]\n' "$@"
echo 'with "$*"'
printf ' [%s]\n' "$*"Мы запустили star.sh с тремя аргументами: a, "b c" и d.
./star.sh a "b c" dwith "$@"
[a]
[b c]
[d]
with "$*"
[a b c d]"$@" передал три аргумента по отдельности, а "$*" соединил их пробелами и передал как один.
Поэтому, чтобы передать полученные аргументы другой команде без изменений, используют "$@".
shift отбрасывает $1 и сдвигает остальные аргументы на одну позицию вперёд. Его используют в скриптах, которые сначала читают одну опцию, а остальное обрабатывают как список файлов.
Мы создали shift.sh, который выводит $1 и $# до и после shift.
#!/bin/bash
echo "before shift: \$1 = $1, \$# = $#"
shift
echo "after shift: \$1 = $1, \$# = $#"Мы запустили shift.sh с тремя аргументами: -v, a.txt и b.txt.
./shift.sh -v a.txt b.txtbefore shift: $1 = -v, $# = 3
after shift: $1 = a.txt, $# = 2Начиная с десятого аргумента номер заключают в фигурные скобки, как ${10}. Мы создали ten.sh, который выводит $10 и ${10} рядом.
#!/bin/bash
echo "\$10 = $10"
echo "\${10} = ${10}"Мы передали ten.sh 11 аргументов, от a до k.
./ten.sh a b c d e f g h i j k$10 = a0
${10} = j$10 вывелось как a0, то есть $1 с приписанным 0, а ${10} — как десятый аргумент j.
🔲 Симулятор аргументов командной строки
В симуляторе ниже можно передавать в args.sh кавычки, подстановочные знаки и --, а также самому вводить команды и смотреть, как ls и getopt читают опции и как star.sh и shift.sh получают аргументы.
🔢 FAQ & рекомендуемые материалы
Подстановочные знаки
[Спецсимволы оболочки] Подстановочные знаки Linux (метасимволы)
Статья с примерами о том, как выбирать имена файлов подстановочными знаками вроде * и ? и классами символов.
Несколько команд
[Linux] 5 способов объединить команды (точка с запятой, конвейер, амперсанд..)
Статья о пяти способах запускать несколько команд в одной строке с помощью точки с запятой, конвейера, &&, || и &.
Вывод строк
Команда echo: From раскрытие и экранирование
Статья о том, как выводить строки и значения переменных командой echo, и о её опциях.
ℹ️ О партнёрских ссылках
Материалы этого сайта содержат партнёрские ссылки. Если посетитель покупает товар или услугу по такой ссылке, сайт получает комиссию от продавца. При этом сумма, которую платит покупатель (при акционных скидках сумма снижается ↓), не увеличивается. Указанные цены, скидки и наличие актуальны на момент написания и могут отличаться, поэтому перед покупкой уточняйте их у продавца. Товары выбираются и оцениваются по нашим собственным критериям, а комиссия не влияет ни на порядок, ни на содержание обзоров.