Comment utiliser $ * tout en omettant certaines variables d'entrée comme $ 1 et $ 2 dans le script bash?

15

Par exemple,

elif [[ $append = $1 ]]
then
  touch ~/directory/"$2".txt
  echo "$variable_in_question" >> ~/directory/"$2".txt

pour créer un fichier texte contenant toutes les entrées suivantes "$2"ou ajouter un fichier texte existant avec toutes les entrées suivantes "$2", que dois-je utiliser à la place de la "$variable_in_question"ligne 4?

Je veux essentiellement "$*", mais en omettant "$1"et "$2".

Oreoplasme
la source

Réponses:

32

Vous pouvez utiliser l' bashextension des paramètres pour spécifier une plage, cela fonctionne également avec les paramètres de position. Pour $3$nce serait:

"${@:3}" # expands to "$3" "$4" "$5" …
"${*:3}" # expands to "$3 $4 $5 …"

Soyez conscient des deux $@et $*ignorez le premier argument $0. Si vous vous demandez lequel utiliser dans votre cas: il est très probable que vous souhaitiez un devis $@. N'utilisez pas $*sauf si vous ne voulez pas explicitement que les arguments soient cités individuellement.

Vous pouvez l'essayer comme suit:

$ bash -c 'echo "${@:3}"' 0 1 2 3 4 5 6
3 4 5 6
$ echo 'echo "${@:3}"' >script_file
$ bash script_file 0 1 2 3 4 5 6
2 3 4 5 6

Notez que dans le premier exemple $0est rempli avec le premier argument 0tandis que lorsqu'il est utilisé dans un script $0est plutôt rempli avec le nom du script, comme le montre le deuxième exemple. Le nom du script estbash bien sûr le premier argument, juste qu'il n'est normalement pas perçu comme tel - il en va de même pour un script rendu exécutable et appelé "directement". Ainsi, dans le premier exemple, nous avons = , = etc. tandis que dans le second, c'est = , = , = etc .; sélectionne chaque argument commençant par .$00$11$0script_file$10$21${@:3}$3

Quelques exemples supplémentaires pour les plages possibles:

 # two arguments starting with the third
$ bash -c 'echo "${@:3:2}"' 0 1 2 3 4 5 6
3 4
 # every argument starting with the second to last one
 # a negative value needs either a preceding space or parentheses
$ bash -c 'echo "${@: -2}"' 0 1 2 3 4 5 6
5 6
 # two arguments starting with the fifth to last one
$ bash -c 'echo "${@:(-5):2}"' 0 1 2 3 4 5 6
2 3

Lectures complémentaires:

dessert
la source
27

Vous pouvez utiliser la fonction shiftintégrée:

$ help shift
shift: shift [n]
    Shift positional parameters.

    Rename the positional parameters $N+1,$N+2 ... to $1,$2 ...  If N is
    not given, it is assumed to be 1.

    Exit Status:
    Returns success unless N is negative or greater than $#.

Ex. donné

$ cat argtest.bash 
#!/bin/bash

shift 2

echo "$*"

ensuite

$ ./argtest.bash foo bar baz bam boo
baz bam boo
tournevis
la source
3
@Oreoplasm Je pense qu'il vaut la peine de mentionner que l' shiftapproche rendra l'accès impossible $1et $2après que vous les ayez déplacés. Dans votre script que vous utilisez $2aux côtés de $variable_in_question, vous devez soit changer cela, soit utiliser l'approche d'extension des paramètres.
dessert
6
shiftest bon quand le premier ou plusieurs args sont sens particulier et il fait de les choisir dans des variables distinctes ( foo="$1"; bar="$2";ou if [[ something with $1 ]];then blah blah; shift. Mais @ réponse de dessert avec l'approche non destructive est bien dans d' autres cas où vous ne voulez toujours la liste complète plus tard , ou lorsque vous utilisez une syntaxe plus sophistiquée pour sélectionner une plage limitée d'arguments, pas à l'infini, sans introduire d'arguments vides dans une commande si $@elle ne contient pas autant d'éléments.
Peter Cordes
13

En règle générale, vous pouvez copier les paramètres de position dans un tableau, supprimer des indices arbitraires du tableau, puis utiliser le tableau pour développer exactement les indices souhaités, sans perdre vos arguments d'origine.

Par exemple, si je voulais tous les arguments sauf les premier, quatrième et cinquième:

args=( "$@" )
unset args[0] args[3] args[4]
echo "${args[@]}"

Dans la copie, les indices sont décalés de 1, car $0ne fait pas partie de $@.

muru
la source
1
Bien sûr, il est possible de combiner cela, par exemple echo "${args[@]:2}"pour le troisième au dernier argument.
dessert