Script bash pour recevoir et repasser les paramètres cités

98

J'essaie d'obtenir les paramètres cités d'un script bash pour être reçus en toute sécurité par un script imbriqué. Des idées?

test.sh

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

myecho.sh

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

Échantillon:

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

Résultat:

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

Résultat recherché

aaa bbb "ccc ddd"
aaa
bbb
ccc ddd
chilltemp
la source
2
J'étais sur le point de poser cette question! Bon timing.
Scottie T

Réponses:

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

Notez que la construction "$ @" n'est pas spécifique à bash et devrait fonctionner avec n'importe quel shell POSIX (elle le fait au moins avec un tiret). Notez également que compte tenu de la sortie souhaitée, vous n'avez pas du tout besoin du niveau supplémentaire de devis. IE appelle simplement le script ci-dessus comme:

./test.sh 1 2 "3 4"
pixelbeat
la source
5
"$ @" fonctionne avec n'importe quel shell Bourne ou dérivé de Bourne shell (à partir de 1978), y compris Korn et Bash. Probablement 95% du temps, utiliser "$ @" est correct et $ * est faux.
Jonathan Leffler
Agréable! Mais, connaissez-vous quelqu'un s'il existe un moyen de le stocker "tel quel" dans une variable? L'original $@n'est pas disponible dans une fonction (car il est écrasé par des arguments de fonction). J'ai essayé foovar="$@"et foovar=$@+ "$foovar"dans la fonction et aucun n'a fonctionné: - /
bitifet
143

Vous voulez utiliser "$ @" (dollar cité à) pour passer des paramètres à un indice. Ainsi ....

ls-color.sh:

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


Quant à savoir pourquoi .....

Depuis la page de manuel Bash :

$*- S'étend aux paramètres de position, à partir de un. Lorsque l'expansion se produit entre guillemets doubles, elle se développe en un seul mot avec la valeur de chaque paramètre séparée par le premier caractère de la variable spéciale IFS. Autrement dit, "$*"équivaut à "$1c$2c...", où c est le premier caractère de la valeur de la variable IFS. Si IFS n'est pas défini, les paramètres sont séparés par des espaces. Si IFS est nul, les paramètres sont joints sans séparateurs intermédiaires.

$@- S'étend aux paramètres de position, à partir de un. Lorsque le développement se produit entre guillemets, chaque paramètre se développe en un mot distinct. Autrement dit, "$@"équivaut à "$1" "$2" ...Si l'expansion entre guillemets doubles se produit dans un mot, l'expansion du premier paramètre est jointe à la partie de début du mot d'origine et l'expansion du dernier paramètre est jointe à la dernière partie de l'original mot. Lorsqu'il n'y a pas de paramètres de position, "$@"et $@étendre à rien (c'est-à-dire qu'ils sont supprimés).


Configuration de certains scripts de démonstration ...

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 est une transformation d'identité pour renvoyer des arguments à un sous-shell (~ 99% du temps, c'est ce que vous vouliez faire):

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

"$*"- quoted-dollar-star écrase les arguments en une seule chaîne (~ 1% du temps où vous voulez réellement ce comportement, par exemple dans un conditionnel:) if [[ -z "$*" ]]; then ...:

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

$*/ $@- sans guillemets, les deux formulaires suppriment un niveau de citation et interprètent les espaces des chaînes sous-jacentes mais ignorent les caractères de citation (presque toujours, c'est une erreur):

./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

Si vous voulez vous amuser, vous pouvez utiliser "$ @" pour imbriquer les choses aussi profondément que vous le souhaitez, en poussant et en faisant sauter des éléments de la pile d'arguments si vous le souhaitez.

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"
Dave Dopson
la source
1
Merci pour l'explication. Juste utilisé "$ *" pour l'alias grep.
darkless
Vous sauvez ma journée!
xyz