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"в функции, но ничего не
получилось
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 имеет значение NULL, параметры объединяются без промежуточных разделителей.

$@- Расширяется до позиционных параметров, начиная с единицы. Когда раскрытие происходит в двойных кавычках, каждый параметр заменяется отдельным словом. То есть "$@"эквивалентно "$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"

"$*"- quoted-dollar-star разбивает аргументы в одну строку (~ 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.
darkless 05
Ты спас мне день!
xyz