Verarbeiten Sie alle Argumente außer dem ersten (in einem Bash-Skript).


444

Ich habe ein einfaches Skript, in dem das erste Argument für den Dateinamen reserviert ist und alle anderen optionalen Argumente an andere Teile des Skripts übergeben werden sollten.

Mit Google habe ich dieses Wiki gefunden , aber es lieferte ein wörtliches Beispiel:

echo "${@: -1}"

Ich kann nichts anderes zum Arbeiten bringen, wie:

echo "${@:2}"

oder

echo "${@:2,1}"

Ich bekomme "Bad Substitution" vom Terminal.

Was ist das Problem und wie kann ich alle bis auf das erste an ein Bash-Skript übergebenen Argument verarbeiten?


21
Um nach anderen verwirrten Personen zu rufen, wurde der falsche Schebang bereitgestellt, der dazu führte "{@:2}", dass er nicht funktionierte, weshalb die richtige Antwort oben übereinstimmt.
Guvante

3
Sie haben gerade die Standard-Shell verwendet, die unter Ubuntu und vielen anderen Linuxes Dash ist. Im Bindestrich wird "$ {@: -1}" wie folgt interpretiert: {parameter: -word} - Standardwerte verwenden und word verwenden, wenn der Parameter nicht definiert oder null ist. Im Bindestrich ergibt "$ {@: -1}" genau das gleiche Ergebnis wie "$ @". Um bash zu verwenden, verwenden Sie einfach die folgende erste Zeile in der Skriptdatei: #! / Bin / bash
luart

Antworten:


659

Benutze das:

echo "${@:2}"

Die folgende Syntax:

echo "${*:2}"

würde auch funktionieren, wird aber nicht empfohlen, da, wie @Gordon bereits erklärt hat, bei der Verwendung *alle Argumente zusammen als ein einziges Argument mit Leerzeichen ausgeführt werden, während @die Unterbrechungen zwischen ihnen beibehalten werden (auch wenn einige der Argumente selbst Leerzeichen enthalten ). Es macht keinen Unterschied mit echo, aber es ist wichtig für viele andere Befehle.


7
Ich habe gerade gemerkt, dass mein Scheiß schlecht ist: #!/usr/bin/env shDeshalb hatte ich Probleme. Ihr Beispiel funktioniert gut, wie oben angegeben, nachdem ich diesen Shebang
Theta

110
Verwenden Sie "${@:2}"stattdessen - using *führt alle Argumente zusammen als ein einziges Argument mit Leerzeichen aus, wobei @die Unterbrechungen zwischen ihnen beibehalten werden (auch wenn einige der Argumente selbst Leerzeichen enthalten). Der Unterschied ist bei nicht spürbar echo, aber für viele andere Dinge von Bedeutung.
Gordon Davisson

2
@ GordonDavisson Der springende Punkt hier ist, die Argumente zusammen auszuführen. Würden wir Dateinamen übergeben, wären Sie richtig. echoverzeiht genug, um sie für Sie zu verketten; andere Befehle sind möglicherweise nicht so nett. Verwenden Sie nicht nur das eine oder andere: Lernen Sie den Unterschied zwischen *und @und wann Sie jedes verwenden müssen. Sie sollten sie ungefähr gleich verwenden. Ein gutes Beispiel dafür, wann dies ein Problem sein wird: Wenn es $3einen Zeilenumbruch ( \n) enthält, wird dieser durch ein Leerzeichen ersetzt, sofern Sie eine Standardvariable haben $IFS.
Zenexer

1
@Zenexer: Soweit ich weiß, war die Frage, wie alle bis auf das erste Argument an "an einen anderen Teil des Skripts" übergeben werden können, wobei dies echonur als Beispiel dient. In diesem Fall sollten sie nicht zusammen ausgeführt werden. Nach meiner Erfahrung sind Situationen, in denen Sie möchten, dass sie zusammen ausgeführt werden, selten (siehe diese Frage für ein Beispiel ) und "$@"fast immer das, was Sie möchten. Das Problem, das Sie bei einem Zeilenumbruch erwähnen, tritt nur auf, wenn $@(oder $*) nicht in doppelte Anführungszeichen steht.
Gordon Davisson

@ GordonDavisson Hmm ... du hast recht, jetzt wo ich darüber nachdenke; Der Zeilenumbruch sollte kein Problem sein. Ich muss an etwas anderes gedacht haben. Ich muss mich jedoch immer noch nicht darüber einig sein, sie zusammen zu führen. Ich muss $*ziemlich oft in meinen Skripten verwenden.
Zenexer

180

Wenn Sie eine Lösung /bin/shsuchen , die auch funktioniert, versuchen Sie es

first_arg="$1"
shift
echo First argument: "$first_arg"
echo Remaining arguments: "$@"

shift [n]verschiebt die Positionsparameter n- mal. A shiftsetzt den Wert von $1auf den Wert von $2, den Wert von $2auf den Wert von $3usw. und verringert den Wert von $#um eins.


25
+1: Sie sollten wahrscheinlich 1 $ in eine Variable einsparen, bevor Sie sie wegschieben.
Glenn Jackman

3
Überraschenderweise foo=shiftnicht das, was ich erwarten würde.
Keith Smiley

Ich weiß, dass dies alt ist, aber versuchen Siefoo=$(shift)
raumaan kidwai

12
@raumaankidwai Das funktioniert aus zwei Gründen nicht: 1) shift(in der Shell) hat keine Ausgabe. Es wirft einfach $1alles weg und verschiebt es nach unten. 2) $(...)Startet eine Subshell, die ihre eigenen lokalen Argumente hat. Es verschiebt die Argumente in der Unterschale, was die Eltern nicht betrifft
Ben Jackson

Danke :) Gibt es eine Möglichkeit, was somecommand "$1" "${@:2}"mit dieser Methode zu tun ist (dh "inline" verschieben)?
Anonym


0

Kam über diese Suche nach etwas anderem. Während der Beitrag ziemlich alt aussieht, wird die einfachste Lösung in Bash unten dargestellt (mindestens Bash 4), set -- "${@:#}"wobei # die Startnummer des Array-Elements ist, das wir vorwärts beibehalten möchten:

    #!/bin/bash

    someVar="${1}"
    someOtherVar="${2}"
    set -- "${@:3}"
    input=${@}

    [[ "${input[*],,}" == *"someword"* ]] && someNewVar="trigger"

    echo -e "${someVar}\n${someOtherVar}\n${someNewVar}\n\n${@}"

Grundsätzlich set -- "${@:3}"werden die ersten beiden Elemente im Array wie die Perl- Verschiebung einfach entfernt und alle verbleibenden Elemente einschließlich des dritten beibehalten. Ich vermute, es gibt auch eine Möglichkeit, die letzten Elemente zu entfernen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.