Wie verwende ich $ *, während bestimmte Eingabevariablen wie $ 1 und $ 2 im Bash-Skript weggelassen werden?

15

Beispielsweise,

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

Was würde ich anstelle der in Zeile 4 verwenden, um entweder eine Textdatei mit allen folgenden Eingaben zu erstellen "$2"oder eine vorhandene Textdatei mit allen folgenden Eingaben anzuhängen ?"$2""$variable_in_question"

Ich will im Grunde "$*"aber weglassen "$1"und "$2".

Oreoplasma
quelle

Antworten:

32

Sie können die bashParametererweiterung verwenden , um einen Bereich anzugeben. Dies funktioniert auch mit Positionsparametern. Für $3... $nwäre es:

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

Seien Sie sich dessen bewusst $@und $*ignorieren Sie das erste Argument $0. Wenn Sie sich fragen, welche Sie in Ihrem Fall verwenden sollen, ist es sehr wahrscheinlich, dass Sie ein Angebot wünschen $@. Verwenden $*Sie diese Option nur, wenn Sie ausdrücklich nicht möchten, dass die Argumente einzeln in Anführungszeichen gesetzt werden.

Sie können es wie folgt ausprobieren:

$ 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

Beachten Sie, dass das erste Beispiel $0mit dem ersten Argument gefüllt ist, 0während in einem Skript $0stattdessen der Name des Skripts verwendet wird, wie das zweite Beispiel zeigt. Der Name des Skripts bashnatürlich ist das erste Argument, nur , dass es normalerweise nicht als solche wahrgenommen - das gleiche gilt für ein Skript ausführbar gemacht und „direkt“ genannt. Im ersten Beispiel haben wir also $0= 0, $1= 1usw., während es im zweiten $0= script_file, $1= 0, $2= 1usw. ist; ${@:3}Wählt jedes Argument aus, das mit beginnt $3.

Einige zusätzliche Beispiele für mögliche Bereiche:

 # 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

Weitere Lektüre:

Dessert
quelle
27

Sie können das shifteingebaute verwenden:

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

$ cat argtest.bash 
#!/bin/bash

shift 2

echo "$*"

dann

$ ./argtest.bash foo bar baz bam boo
baz bam boo
Stahlfahrer
quelle
3
@Oreoplasm Ich denke, es ist erwähnenswert, dass der shiftAnsatz es unmöglich macht, darauf zuzugreifen, $1und $2nachdem Sie sie verschoben haben. In Ihrem Skript, das Sie $2neben dem verwenden $variable_in_question, müssen Sie entweder das ändern oder den Parametererweiterungsansatz verwenden.
Dessert
6
shiftgut ist , wenn das erste ein oder mehrere Argumente sind speziell und es macht Sinn , sie in separates Variablen herausgreifen ( foo="$1"; bar="$2";oder if [[ something with $1 ]];then blah blah; shift. Aber @ Antwort des Desserts mit dem nicht-destruktiven Ansatz ist schön , in anderen Fällen , wenn Sie es später noch die vollständige Liste wollen , oder wenn Sie eine schickere Syntax verwenden, um einen begrenzten Bereich von Argumenten auszuwählen, nicht unendlich, ohne leere Argumente in einen Befehl einzufügen, wenn $@nicht so viele Elemente vorhanden sind.
Peter Cordes
13

Im Allgemeinen können Sie die Positionsparameter in ein Array kopieren, beliebige Indizes des Arrays löschen und das Array dann verwenden, um genau die gewünschten Indizes anzuzeigen, ohne die ursprünglichen Argumente zu verlieren.

Wenn ich zum Beispiel alle Argumente außer dem ersten, vierten und fünften haben möchte:

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

In der Kopie werden die Indizes um 1 verschoben, da dies $0nicht Teil von ist $@.

muru
quelle
1
Natürlich ist es möglich, das zu kombinieren, zB echo "${args[@]:2}"für das drittletzte Argument.
Dessert