Come posso usare $ * mentre ometto determinate variabili di input come $ 1 e $ 2 nello script bash?


15

Per esempio,

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

per creare un file di testo contenente tutti gli input seguenti "$2"o aggiungere un file di testo esistente con tutti gli input seguenti "$2", cosa dovrei usare al posto della "$variable_in_question"riga 4?

Fondamentalmente voglio "$*", ma omettendo "$1"e "$2".

Risposte:


32

È possibile utilizzare l' bashespansione dei parametri per specificare un intervallo, funziona anche con i parametri posizionali. Per $3... $nsarebbe:

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

Sii consapevole di entrambi $@e $*ignora il primo argomento $0. Se ti chiedi quale utilizzare nel tuo caso: è molto probabile che tu voglia un preventivo $@. Non utilizzare $*a meno che esplicitamente non si desidera che gli argomenti da citare singolarmente.

Puoi provarlo come segue:

$ 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

Si noti che nel primo esempio $0è riempito con il primo argomento 0mentre quando usato in uno script $0è invece riempito con il nome dello script, come mostra il secondo esempio. Il nome del script bash, naturalmente, è il primo argomento, solo che è normalmente non percepita come tale - lo stesso vale per uno script fatto eseguibile e chiamato “direttamente”. Quindi nel primo esempio abbiamo $0= 0, $1= 1etc mentre nel secondo è $0= script_file, $1= 0, $2= 1etc .; ${@:3}seleziona ogni argomento che inizia con $3.

Alcuni esempi aggiuntivi per possibili intervalli:

 # 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

Ulteriori letture:


27

Puoi usare il shiftbuiltin:

$ 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. dato

$ cat argtest.bash 
#!/bin/bash

shift 2

echo "$*"

poi

$ ./argtest.bash foo bar baz bam boo
baz bam boo

3
@Oreoplasma Penso che valga la pena ricordare che l' shiftapproccio renderà impossibile l'accesso $1e $2dopo averli spostati. Nel tuo script che utilizzi $2insieme a $variable_in_question, è necessario modificarlo o utilizzare l'approccio Parameter Expansion.
dessert

6
shiftè buona quando la prima una o più argomenti sono speciali e ha senso prenderli fuori in variabili separate ( foo="$1"; bar="$2";o if [[ something with $1 ]];then blah blah; shift. Ma @ risposta di dessert con l'approccio non distruttivo è bello in altri casi in cui si fa vuole ancora l'elenco completo tardi o quando usi la sintassi più elaborata per selezionare una gamma limitata di argomenti, non verso l'infinito, senza introdurre argomenti vuoti a un comando se $@non ha così tanti elementi.
Peter Cordes

13

In genere, è possibile copiare i parametri posizionali in un array, eliminare indici arbitrari dell'array e quindi utilizzare l'array per espandere esattamente gli indici desiderati, senza perdere gli argomenti originali.

Ad esempio, se volessi tutti gli argomenti tranne il primo, il quarto e il quinto:

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

Nella copia, gli indici vengono spostati di 1, poiché $0non fa parte di $@.


1
Naturalmente è possibile combinarlo, ad esempio echo "${args[@]:2}"per il terzo all'ultimo argomento.
dessert
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.