Converti gli argomenti della riga di comando in un array in Bash


162

Come posso convertire gli argomenti della riga di comando in un array di script bash?

Voglio prendere questo:

./something.sh arg1 arg2 arg3

e convertilo in

myArray=( arg1 arg2 arg3 )

in modo che io possa usare myArray per un ulteriore uso nello script.

Questo precedente post SO si avvicina, ma non spiega come creare un array: come posso analizzare gli argomenti della riga di comando in Bash?

Ho bisogno di convertire gli argomenti in un normale array di script bash; Mi rendo conto che potrei usare altri linguaggi (Python, per esempio) ma devo farlo in bash. Immagino che sto cercando una funzione "append" o qualcosa di simile?

AGGIORNAMENTO: Volevo anche chiedere come verificare la presenza di argomenti zero e assegnare un valore di array predefinito e, grazie alla risposta seguente, sono riuscito a farlo funzionare:

if [ "$#" -eq 0 ]; then
  myArray=( defaultarg1 defaultarg2 )
else
  myArray=( "$@" )
fi

Risposte:


208

In realtà i tuoi argomenti da riga di comando sono praticamente come un array già. Almeno, puoi trattare la $@variabile in modo molto simile a un array. Detto questo, puoi convertirlo in un array reale come questo:

myArray=( "$@" )

Se vuoi solo digitare alcuni argomenti e inserirli nel $@valore, usa set:

$ set -- apple banana "kiwi fruit"
$ echo "$#"
3
$ echo "$@"
apple banana kiwi fruit

Comprendere come utilizzare la struttura degli argomenti è particolarmente utile in POSIX sh, che non ha nient'altro come un array.


2
Grazie! Funziona alla grande! Stavo per chiedere come verificare la presenza di argomenti zero e assegnare un valore di array predefinito, e $ # funziona perfettamente per questo!
Suman,

1
setconsente di impostare parametri posizionali per l'ambito. Inoltre, consente di impostare le opzioni della shell. Puoi farlo set foo, il che significa che si $1espande in "pippo", ma se i tuoi parametri iniziano con un trattino setassumerai che intendi impostare un'opzione di shell. Il doppio trattino assicura che tutti i seguenti parametri siano interpretati come parametri posizionali da impostare.
Kojiro,

12
One gotcha: echo $@stamperà tutti gli argomenti, ma echo $myArraystamperà solo il primo elemento. Per vederli tutti, usa echo ${myArray[@]}.
z0r

4
@ z0r Se non si inseriscono doppie virgolette attorno a quelle espansioni, bash le rielaborerà, e probabilmente perderà di significato.
Kojiro,

Esatto, il modo generale di "splat" di un array e usare ogni elemento è "${myArray[@]}". Se si desidera eseguire il loop nell'array, sono necessarie le virgolette per evitare di dividere i suoi singoli elementi su IFS
BallpointBen

66

Forse questo può aiutare:

myArray=("$@") 

inoltre puoi ripetere gli argomenti omettendo 'in':

for arg; do
   echo "$arg"
done

sarà equivalente

for arg in "${myArray[@]}"; do
   echo "$arg"
done

3
Domande per principianti: in che modo bash sa cosa inserire nel argcampo: è una variabile predefinita? ${var}viene esteso al contenuto di var. ${var[n]}viene espanso al contenuto dell'elemento ndell'array var. Si sta ${var[@]}quindi espandendo l'intero array, ovvero ${var[0]} ${var[1]} ... ${var[n]}(con nl'indice dell'ultimo elemento)?
Christian,

4
[for] senza [in] eseguirà il ciclo sugli argomenti array $ @ ($ 1, $ 2, ecc.). Che può essere impostato anche con il comando [set], ad esempio set - arg1 arg2
Nahuel

17

In realtà è possibile accedere all'elenco dei parametri con $1 $2 ...ecc.
Che è esattamente equivalente a:

${!i}

Quindi, l'elenco dei parametri può essere modificato con set
ed ${!i}è il modo corretto di accedervi:

$ set -- aa bb cc dd 55 ff gg hh ii jjj kkk lll
$ for ((i=0;i<=$#;i++)); do echo "$#" "$i" "${!i}"; done
12 1 aa
12 2 bb
12 3 cc
12 4 dd
12 5 55
12 6 ff
12 7 gg
12 8 hh
12 9 ii
12 10 jjj
12 11 kkk
12 12 lll

Per il tuo caso specifico, questo potrebbe essere usato (senza la necessità di array), per impostare l'elenco di argomenti quando non ne è stato fornito nessuno:

if [ "$#" -eq 0 ]; then
    set -- defaultarg1 defaultarg2
fi

che si traduce in questa espressione ancora più semplice:

[ "$#" == "0" ] && set -- defaultarg1 defaultarg2

L'esempio dell'eco non dovrebbe essere: echo "$#" "$i+1" "${!i}";ottenere l'output esattamente come mostrato?
Zael,

6

Ecco un altro utilizzo:

#!/bin/bash
array=( "$@" )
arraylength=${#array[@]}
for (( i=0; i<${arraylength}; i++ ));
do
   echo "${array[$i]}"
done

4

Più facile Eppure, puoi operare direttamente su $@;)

Ecco come fare per passare un elenco di argomenti direttamente dal prompt:

function echoarg { for stuff in "$@" ; do echo $stuff ; done ; } 
    echoarg Hey Ho Lets Go
    Hey
    Ho
    Lets
    Go

1
Ancora più semplice, for stuff in "$@" ; do ...è uguale a for stuff ; do ...:)
kkm

1

Vista affiancata di come l'array e $ @ siano praticamente gli stessi.

Codice:

#!/bin/bash

echo "Dollar-1 : $1"
echo "Dollar-2 : $2"
echo "Dollar-3 : $3"
echo "Dollar-AT: $@"
echo ""

myArray=( "$@" )

echo "A Val 0: ${myArray[0]}"
echo "A Val 1: ${myArray[1]}"
echo "A Val 2: ${myArray[2]}"
echo "A All Values: ${myArray[@]}"

Ingresso:

./bash-array-practice.sh 1 2 3 4

Produzione:

Dollar-1 : 1
Dollar-2 : 2
Dollar-3 : 3
Dollar-AT: 1 2 3 4

A Val 0: 1
A Val 1: 2
A Val 2: 3
A All Values: 1 2 3 4

1

È importante sottolineare l'importanza delle doppie virgolette. Supponiamo che un argomento contenga spazi bianchi.

Codice:

#!/bin/bash
printf 'arguments:%s\n' "$@"
declare -a arrayGOOD=( "$@" )
declare -a arrayBAAD=(  $@  )

printf '\n%s:\n' arrayGOOD
declare -p arrayGOOD
arrayGOODlength=${#arrayGOOD[@]}
for (( i=1; i<${arrayGOODlength}+1; i++ ));
do
   echo "${arrayGOOD[$i-1]}"
done

printf '\n%s:\n' arrayBAAD
declare -p arrayBAAD
arrayBAADlength=${#arrayBAAD[@]}
for (( i=1; i<${arrayBAADlength}+1; i++ ));
do
   echo "${arrayBAAD[$i-1]}"
done

Produzione:

> ./bash-array-practice.sh 'The dog ate the "flea" -- and ' the mouse.
arguments:The dog ate the "flea" -- and 
arguments:the
arguments:mouse.

arrayGOOD:
declare -a arrayGOOD='([0]="The dog ate the \"flea\" -- and " [1]="the" [2]="mouse.")'
The dog ate the "flea" -- and 
the
mouse.

arrayBAAD:
declare -a arrayBAAD='([0]="The" [1]="dog" [2]="ate" [3]="the" [4]="\"flea\"" [5]="--" [6]="and" [7]="the" [8]="mouse.")'
The
dog
ate
the
"flea"
--
and
the
mouse.
> 
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.