654 votes

Traite tous les arguments sauf le premier (dans un script bash)

J'ai un simple script où le premier argument est réservé au nom de fichier, et tous les autres arguments optionnels doivent être passés à d'autres parties du script.

En utilisant Google, j'ai trouvé ce wiki mais elle a fourni un exemple concret :

echo "${@: -1}"

Je n'arrive pas à faire fonctionner autre chose, comme :

echo "${@:2}"

ou

echo "${@:2,1}"

J'obtiens "Bad substitution" dans le terminal.

Quel est le problème, et comment puis-je traiter tous les arguments sauf le premier passé à un bash script ?

39 votes

Pour appeler tous ceux qui ont été confondus, le mauvais shebang a été fourni en causant "{@:2}" ne fonctionne pas, c'est pourquoi la bonne réponse correspond à la réponse ci-dessus.

6 votes

Vous avez juste utilisé le shell par défaut, qui est dash sur Ubuntu et beaucoup d'autres Linuxes. En dash "${@ : -1}" est interprété comme : {parameter:-word} - Utiliser les valeurs par défaut, et utiliser word si le paramètre n'est pas défini ou est nul. Donc, en tiret "${@ : -1}" donne exactement le même résultat que "$@". Pour utiliser bash, il suffit d'utiliser la première ligne suivante dans le fichier script : #!/bin/bash

953voto

Oli Charlesworth Points 148744

Utilisez ça :

echo "${@:2}"

La syntaxe suivante :

echo "${*:2}"

fonctionnerait aussi bien, mais n'est pas recommandé, car en tant que @Gordon déjà expliqué, que l'utilisation * il exécute tous les arguments ensemble comme un seul argument avec des espaces, alors que @ préserve les coupures entre eux (même si certains des arguments eux-mêmes contiennent des espaces). Cela ne fait pas la différence avec echo mais il est important pour de nombreuses autres commandes.

9 votes

Je viens de me rendre compte que mon shebang était mauvais : #!/usr/bin/env sh C'est pourquoi j'ai eu des problèmes. Votre exemple fonctionne bien, comme celui fourni plus haut, après que j'ai supprimé tout cela.

134 votes

Utilisez "${@:2}" à la place -- en utilisant * exécute tous les arguments ensemble comme un seul argument avec des espaces, tandis que @ préserve les coupures entre eux (même si certains des arguments eux-mêmes contiennent des espaces). La différence n'est pas perceptible avec echo mais il est important pour beaucoup d'autres choses.

3 votes

@GordonDavisson Le but ici est d'exécuter les arguments ensemble. Si nous passions des noms de fichiers, vous auriez raison. echo est assez indulgente pour les concaténer pour vous ; d'autres commandes peuvent ne pas être aussi gentilles. N'utilisez pas seulement l'un ou l'autre : apprenez la différence entre * et @ et quand les utiliser. Vous devriez les utiliser à peu près également. Un bon exemple de cas où cela peut poser problème : si $3 contient un saut de ligne ( \n ), il sera remplacé par un espace, à condition que vous disposiez d'une valeur par défaut. $IFS variable.

243voto

Ben Jackson Points 28358

Si vous souhaitez une solution qui fonctionne également dans /bin/sh essayez

first_arg="$1"
shift
echo First argument: "$first_arg"
echo Remaining arguments: "$@"

shift [n] déplace les paramètres de position n temps. A shift définit la valeur de $1 à la valeur de $2 la valeur de $2 à la valeur de $3 et ainsi de suite, en diminuant la valeur de $# par un.

29 votes

+1 : Vous devriez probablement enregistrer 1 $ dans une variable avant de le déplacer.

3 votes

Étonnamment foo=shift ne fait pas ce que j'attendais.

1 votes

Je sais que c'est vieux, mais essaie foo=$(shift)

66voto

walknotes Points 340

Travailler en version bash 4 ou supérieure :

#!/bin/bash
echo "$0";         #"bash"
bash --version;    #"GNU bash, version 5.0.3(1)-release (x86_64-pc-linux-gnu)"

En fonction :

echo $@;              #"p1" "p2" "p3" "p4" "p5"
echo ${@: 0};  #"bash" "p1" "p2" "p3" "p4" "p5"
echo ${@: 1};         #"p1" "p2" "p3" "p4" "p5"
echo ${@: 2};              #"p2" "p3" "p4" "p5"
echo ${@: 2:1};            #"p2"
echo ${@: 2:2};            #"p2" "p3"
echo ${@: -2};                       #"p4" "p5"
echo ${@: -2:1};                     #"p4"

Notez l'espace entre ':' et '-', sinon cela signifie autre chose :

${var:-word} Si var est nul ou non défini,
est substitué à var. La valeur de var ne change pas.

${var:+word} Si var est défini,
est substitué à var. La valeur de var ne change pas.

Qui est décrit dans : Unix / Linux - Substitution du shell

7voto

user411279 Points 415

Il s'agit simplement d'un commentaire dans une réponse. Je suis d'accord avec Gordon Davisson, vous devriez probablement utiliser "${@:2}".

4voto

OnlineCop Points 1498

http://wiki.bash-hackers.org/scripting/posparams

Il explique l'utilisation de shift (si vous voulez rejeter les N premiers paramètres) et ensuite Mise en œuvre de l'utilisation de la masse

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X