web-dev-qa-db-fra.com

$ @ sauf le 1er argument

J'ai besoin d'écrire un script Shell qui s'exécute de cette façon:

./myscript arg1 arg2_1 arg2_2 arg2_3 ....... arg2_#

il y a une boucle for à l'intérieur du script

for i in $@

Cependant, comme je le sais, $ @ comprend 1 $ jusqu'à $ ($ # - 1). Mais pour mon programme, 1 $ est très différent de 2 $ 3 $ 4 $, etc. Je voudrais boucler de 2 $ à la fin ... Comment y arriver? Je vous remercie:)

46
user40780

Tout d'abord, notez que $@ Sans guillemets n'a aucun sens et ne doit pas être utilisé. $@ Ne doit être utilisé qu'entre guillemets ("$@") Et dans des contextes de liste.

for i in "$@" Est considéré comme un contexte de liste, mais ici, pour parcourir les paramètres de position, la forme canonique, la plus portable et la plus simple est:

for i
do something with "$i"
done

Maintenant, pour parcourir les éléments à partir du second, la manière canonique et la plus portable est d'utiliser shift:

first_arg=$1
shift # short for shift 1
for i
do something with "$i"
done

Après shift, ce qui était $1 A été supprimé de la liste (mais nous l'avons enregistré dans $first_arg) Et ce qui était dans $2 est maintenant dans $1. Les paramètres de position ont été décalé1 Position vers la gauche (utilisez shift 2 Pour décaler de 2 ...). Donc, fondamentalement, notre boucle est en boucle de ce qui était le deuxième argument au dernier.

Avec bash (et zsh et ksh93, Mais c'est tout), une alternative est de faire:

for i in "${@:2}"
do something with "$i"
done

Mais notez que ce n'est pas la syntaxe standard de sh donc ne doit pas être utilisée dans un script qui commence par #! /bin/sh -.

Dans zsh ou yash, vous pouvez également faire:

for i in "${@[3,-3]}"
do something with "$i"
done

pour boucler du 3ème au 3ème dernier argument.

Dans zsh, $@ Est également appelé tableau $argv. Donc, pour faire apparaître des éléments depuis le début ou la fin des tableaux, vous pouvez également faire:

argv[1,3]=() # remove the first 3 elements
argv[-3,-1]=()

(shift peut également être écrit 1=() dans zsh)

Dans bash, vous ne pouvez affecter que les éléments $@ Avec la fonction intégrée set, donc pour faire sauter 3 éléments à la fin, ce serait quelque chose comme:

set -- "${@:1:$#-3}"

Et pour boucler du 3ème au 3ème dernier:

for i in "${@:3:$#-5}"
do something with "$i"
done

POSIX, pour faire apparaître les 3 derniers éléments de "$@", Vous devez utiliser une boucle:

n=$(($# - 3))
for arg do
  [ "$n" -gt 0 ] && set -- "$@" "$arg"
  shift
  n=$((n - 1))
done
55
Stéphane Chazelas

Je pense que vous voulez que le shift soit intégré. Il renomme $2 à $1, $3 à $2, etc.

Comme ça:

shift
for i in "$@"; do
    echo $i
done
10
John

Il y a toujours l'approche des hommes des cavernes:

first=1
for i
do
        if [ "$first" ]
        then
                first=
                continue
        fi
        something with "$i"
done

Cela laisse $@ intact (au cas où vous voudriez l'utiliser plus tard), et boucle simplement sur chaque argument, mais ne traite pas le premier.

2
Scott

En bash, vous pouvez également écrire cette boucle avec une indexation explicite:

for ((i=2; i<=$#; ++i)); do
  process "${!i}"
done

Cela itère sur tous les arguments du second au dernier. Si vous souhaitez exclure le dernier argument à la place, faites simplement ceci

for ((i=1; i<=$#-1; ++i)); do
  process "${!i}"
done

et si vous voulez seulement prendre tous les autres arguments, écrivez-le

for ((i=1; i<=$#; i+=2)); do
  process "${!i}"
done

L'histoire derrière ceci est la version arithmétique du for builtin , combinée avec le argument-count $#) = et indirection variable ${…} .

Une application intéressante est que vous pouvez l'utiliser pour décider, à l'intérieur de la boucle, si une option donnée prendra l'argument qui la suit comme valeur. Si c'est le cas, incrémentez i (par exemple en écrivant : $((++i))) pour consommer la valeur suivante et sautez-la pendant l'itération.

1
MvG