Bash: Візьміть перший аргумент командного рядка, а решту передайте


82

Приклад:

check_prog hostname.com /bin/check_awesome -c 10 -w 13

check_remote -H $HOSTNAME -C "$ARGS"
#To be expanded as
check_remote -H hostname.com -C "/bin/check_awesome -c 10 -w 13"

Сподіваюся, вищесказане має сенс. Аргументи зміняться, оскільки я буду використовувати це приблизно для 20+ команд. Це дивний метод обгортання програми, але його можна обійти. Кілька проблем з кількома системами, які ми використовуємо тут (Повинен мати код кохання з 70-х)

Вищезаписане можна написати на perl або python, але найкращим методом буде Bash

Відповіді:


107

Ви можете використовувати shift

shift - це вбудована оболонка, яка працює на позиційних параметрах. Кожного разу, коли ви викликаєте shift, він "зміщує" всі позиційні параметри на один. $ 2 стає $ 1, $ 3 стає $ 2, $ 4 стає $ 3 тощо

приклад:

$ function foo() { echo $@; shift; echo $@; } 
$ foo 1 2 3
1 2 3
2 3

9
Чудово! Працює як шарм echo $1 shift echo $* - це приклад того, як використовувати shift для майбутніх людей, які шукають це, запустити його як ./script.sh cmd1 cmd2 cmd3 cmd4і встановить $ 1 до cmd1, а решта буде cmd2 cmd3 cmd4, як я хотів
user554005

3
І $#зменшується на 1, якщо це вже не 0. Ви також можете дати shiftчисловий аргумент для зсуву більш ніж на одне місце.
Кіт Томпсон,

8
@ user554005: Майже завжди слід використовувати echo "$@"замість echo $*або echo "$*"оскільки форма без котирувань та цитована $*форма "згладжують" аргументи, які зазвичай не потрібні.
Денніс Вільямсон

1
Тож типовим буде використання SOME_VAR=$1; shift; some_cmd "$*". Зараз some_cmdпередано аргументи 2..n. Чудово працює ... Дякую!
Бред Паркс,

5
@BradParks при передачі імен файлів як аргументів, які будуть прочитані іншою командою, і якщо імена файлів містять пробіли, я думаю, що ви хочете, SOME_VAR=$1; shift; some_cmd "$@"оскільки "$@"гарантує, що пропущені місця будуть передані з косою рискою перед префіксом пробілу. "$*"знизить \ символ (або вирівнюватися ім'я файлу, як описано вище)
modulitos

14

Як програміст, я настійно не рекомендую, shiftоскільки операції, що змінюють стан, можуть впливати на великі частини сценарію та ускладнювати його розуміння, модифікацію та налагодження: sweat_smile :. Ви можете замість цього використовувати наступне:

#!/usr/bin/env bash

all_args=("$@")
first_arg=$1
second_args=$2
rest_args=("${all_args[@]:2}")

echo "${rest_args[@]}"

3
Я настійно рекомендую не зберігати список аргументів у простій рядковій змінній та / або розширювати змінні без подвійних лапок (як REST_ARGSтут). Використовуйте масив (наприклад ALL_ARGS) і розширюйте його [@]двома лапками.
Гордон Девіссон,

1
@GordonDavisson чи можете ви переписати bashфрагмент зі своєю рекомендацією або написати інший фрагмент? Я б дуже хотів це зрозуміти більше і використовувати в деяких bashсценаріях, над якими я зараз працюю. Заздалегідь дякуємо і продовжуйте хорошу роботу!
Абдулла

3
Я відредагував його, щоб показати рекомендовану форму. Зберігання списків аргументів у вигляді рядків втрачає різницю між кількома аргументами та одиничними аргументами, що містять пробіли; розширивши їх без подвійних лапок, буде розділено на всі пробіли (включаючи ті, що спочатку були в аргументах), а також розширено все, що схоже на підстановку назви файлу. Наприклад, якщо запустити оригінал як ./script "foo" "bar" "six * nine", він надрукує "шість <список файлів у поточному каталозі> дев'ять".
Гордон Девіссон,

2
Я також рекомендую назви змінних з нижчим або змішаним регістром, щоб уникнути конфліктів з різними іменами з великими регістрами зі спеціальним значенням. О, і shellcheck.net добре вказує на проблематичне цитування та інші поширені помилки.
Гордон Девіссон,

Дякую @GordonDavisson, тепер я можу писати кращі сценарії BASH, і люди, які слідують моїй відповіді, не повторять мої помилки.
Абдулла
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.