Сценарій Bash для отримання та повторного використання цитованих параметрів


98

Я намагаюся отримати цитовані параметри bash-скрипту, щоб безпечно отримувати вкладений сценарій. Якісь ідеї?

test.sh

#!/bin/bash
echo $*
bash myecho.sh $*

myecho.sh

#!/bin/bash
 echo $1
 echo $2
 echo $3
 echo $4

Зразок:

bash test.sh aaa bbb '"ccc ddd"'

Результат:

aaa bbb "ccc ddd"
aaa
bbb
"ccc
ddd"

Бажаний результат

aaa bbb "ccc ddd"
aaa
bbb
ccc ddd

2
Я ось-ось збирався задати це питання! Гарні терміни.
Scottie T

Відповіді:


70
#!/bin/bash
echo $*
bash myecho.sh "$@"

Зауважте, що конструкція "$ @" не є специфічною для bash і повинна працювати з будь-якою оболонкою POSIX (вона принаймні має тире). Зауважте також, що з огляду на потрібний вихід, вам взагалі не потрібен додатковий рівень цитування. IE просто зателефонуйте до вищевказаного сценарію, як:

./test.sh 1 2 "3 4"

5
"$ @" працює з будь-якою оболонкою Bourne або похідною оболонки Bourne (починаючи з 1978 року), включаючи Korn і Bash. Можливо, у 95% випадків правильне використання "$ @", а $ * - неправильне.
Джонатан Леффлер

Приємно! Але, знайте когось, чи є якийсь спосіб зберегти його "як є" у змінній? Оригінал $@недоступний у функції (оскільки він перезаписаний аргументами функції). Я спробував foovar="$@"і foovar=$@+ "$foovar"у функції, і жодна не працювала: - /
бутиfet

143

Ви хочете використовувати "$ @" (котирується долар у), щоб передати параметри до індексу. Як так….

ls-color.sh:

#!/bin/bash
/bin/ls --color=auto "$@"    # passes though all CLI-args to 'ls'


Щодо того .....

На сторінці чоловіка Bash :

$*- Розширюється на позиційні параметри, починаючи з одиниці. Коли розширення відбувається в межах подвійних лапок, воно розширюється на одне слово зі значенням кожного параметра, розділеним першим символом спеціальної змінної IFS. Тобто, "$*"еквівалентно "$1c$2c...", де c - перший символ значення змінної IFS. Якщо IFS не встановлено, параметри розділяються пробілами. Якщо IFS недійсний, параметри з'єднуються без втручання роздільників.

$@- Розширюється на позиційні параметри, починаючи з одиниці. Коли розширення відбувається в межах подвійних лапок, кожен параметр розширюється на окреме слово. Тобто, "$@"еквівалентно "$1" "$2" ...Якщо розширення з подвійним цитуванням відбувається в межах слова, розширення першого параметра з'єднується з початковою частиною вихідного слова, а розширення останнього параметра з'єднується з останньою частиною оригіналу слово. Коли немає позиційних параметрів, "$@"а також $@розширити нічого (тобто, вони будуть видалені).


Налаштування деяких демо-скриптів ...

echo 'echo -e "\$1=$1\n\$2=$2\n\$3=$3\n\$4=$4"' > echo-params.sh
echo './echo-params.sh $*' > dollar-star.sh
echo './echo-params.sh $@' > dollar-at.sh
echo './echo-params.sh "$*"' > quoted-dollar-star.sh
echo './echo-params.sh "$@"' > quoted-dollar-at.sh
chmod +x *.sh

"$@"- quoted-dollar-at - це трансформація ідентичності для повторної передачі аргументів до нижньої оболонки (~ 99% часу, це ви мали намір зробити):

./quoted-dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2=            
  # $3= 'cc cc'
  # $4= "ddd ddd"

"$*"- зірка з котирувальним доларом розбиває аргументи в єдиний рядок (~ 1% часу, коли ви дійсно бажаєте такої поведінки, наприклад, в умовному випадку if [[ -z "$*" ]]; then ...:):

./quoted-dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa  'cc cc' "ddd ddd"   
  # $2=                     
  # $3=             
  # $4=

$*/ $@- без лапок, обидві форми знімають один рівень котирування та інтерпретують пробіли з нижчих рядків, але ігнорують символи цитат (майже завжди це помилка):

./dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc                  
  # $3= cc'
  # $4= "ddd

./dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc
  # $3= cc'
  # $4= "ddd

Якщо ви хочете повеселитися, ви можете використовувати "$ @", щоб вкласти речі так глибоко, як хочете, відштовхуючи та вискакуючи елементи зі стека аргументів, якщо хочете.

function identity() {
  "$@"
}
set -x
identity identity identity identity identity echo Hello \"World\"
# + identity identity identity identity identity echo Hello '"World"'
# + identity identity identity identity echo Hello '"World"'
# + identity identity identity echo Hello '"World"'
# + identity identity echo Hello '"World"'
# + identity echo Hello '"World"'
# + echo Hello '"World"'
# Hello "World"

1
Дякую за пояснення. Щойно використовується "$ *" для псевдоніму grep.
безтемний

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