$ @ tranne il 1 ° argomento


36

Ho bisogno di scrivere uno script di shell che funziona in questo modo:

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

c'è un ciclo for all'interno dello script

for i in $@

Tuttavia, come so, $ @ include $ 1 fino a $ ($ # - 1). Ma per il mio programma $ 1 è nettamente diverso da $ 2 $ 3 $ 4 ecc. Vorrei passare da $ 2 alla fine ... Come posso ottenere questo? Grazie:)

Risposte:


47

Innanzitutto, nota che $@senza virgolette non ha senso e non dovrebbe essere usato. $@dovrebbe essere usato solo tra virgolette ( "$@") e in contesti di lista.

for i in "$@" si qualifica come un contesto di elenco, ma qui, per passare in rassegna i parametri posizionali, la forma canonica, più portatile e più semplice è:

for i
do something with "$i"
done

Ora, per passare in rassegna gli elementi a partire dal secondo, il modo canonico e più portatile è usare shift:

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

Dopo shift, ciò che era $1stato rimosso è stato rimosso dall'elenco (ma lo abbiamo salvato in $first_arg) e quello che era in $2è ora $1. I parametri posizionali sono stati spostati 1 verso sinistra (usare shift 2per spostare di 2 ...). Quindi, in sostanza, il nostro ciclo sta passando da quello che era il secondo argomento all'ultimo.

Con bash(e zshe ksh93, ma questo è tutto), un'alternativa è fare:

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

Ma nota che non è una shsintassi standard, quindi non dovrebbe essere usata in uno script che inizia con #! /bin/sh -.

In zsho yash, puoi anche fare:

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

per passare dal 3o al 3o ultimo argomento.

In zsh, $@è anche noto come $argvarray. Quindi, per far apparire gli elementi dall'inizio o dalla fine delle matrici, puoi anche fare:

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

( shiftpuò anche essere scritto 1=()in zsh)

In bash, puoi solo assegnare agli $@elementi con l' setintegrato, quindi per estrarre 3 elementi alla fine, sarebbe qualcosa del tipo:

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

E per passare dal 3 ° al 3 ° ultimo:

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

POSIX, per far apparire gli ultimi 3 elementi di "$@", avresti bisogno di usare un loop:

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

2
Una possibilità bash alternativa (e brutta): variabili indirette:for ((i=2; i<=$#; i++)); do something with "${!i}"; done
glenn jackman,

Ho più familiarità con questa versione, dal momento che ho più familiarità con c ++ :)
user40780

10

Penso che tu voglia il shiftbuiltin. Rinomina $2in $1, $3a $2, ecc.

Come questo:

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

potresti spiegare più dettagliatamente come posso realizzarlo nel ciclo for? Grazie.
user40780,

1
Non lo fai - lo usi prima di entrare nel forciclo, quindi fai semplicemente un ciclo attraverso $ @ normalmente. Dopo la shiftchiamata, $ @ dovrebbe esserearg2_1 arg2_2 arg2_3...
John,

Tuttavia, avrò un'altra domanda: supponiamo di voler passare da $ 1 a $ ($ # - 2) (ovvero arg_1 fino a arg_2 _ # - 1, tranne arg_2 _ #) ... Cosa devo fare?
user40780,

2

C'è sempre l'approccio cavernicolo:

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

Questo rimane $@intatto (nel caso in cui si desideri utilizzarlo in un secondo momento) e passa semplicemente su ogni argomento, ma non elabora il primo.


1

In bash puoi anche scrivere quel ciclo con indicizzazione esplicita:

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

Questo scorre su tutti gli argomenti dal secondo all'ultimo. Se invece vuoi escludere l'ultimo argomento, semplicemente fallo

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

e se vuoi solo prendere ogni altro argomento, scrivilo come

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

La storia dietro questa è la versione aritmetica del forbuiltin , combinata con il conteggio$# degli argomenti e il riferimento indiretto variabile${…} .

Una buona applicazione è che puoi usarla per decidere, all'interno del ciclo, se una determinata opzione prenderà l'argomento che la segue come valore. In tal caso, incrementare i(ad es. La scrittura : $((++i))) per consumare il valore successivo e saltarlo durante l'iterazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.