Ist es möglich, auf Indizes in zu verweisen $@
? Ich kann nirgendwo im GrayCat-Wiki einen Verweis finden, der wie folgt verwendet werden kann , und das Advanced Scripting Guide und andere weisen dies einer anderen Variablen zu, bevor sie stattdessen geändert werden.
$ echo ${@[0]}
-bash: ${@[0]}: bad substitution
Das Ziel ist DRY : Das erste Argument wird für eine Sache und der Rest für etwas anderes verwendet, und ich möchte vermeiden, entweder den zu normalisierenden Code $@
oder das Array zu duplizieren oder eine separate Funktion dafür zu erstellen (obwohl dies der Fall ist) Punkt, es ist wahrscheinlich der einfachste Ausweg).
Erläuterung: Ziel war es, die Werte der variablen Länge zu ändern $@
, um das Debuggen des Codes zu vereinfachen. Die aktuelle Version ist etwas zu hackig für meinen Geschmack, obwohl sie auch für bizarre Pfade wie funktioniert
$'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'
Update : Sieht so aus, als wäre das nicht möglich. Der Code verwendet jetzt sowohl Code- als auch Datenvervielfältigung, funktioniert aber zumindest:
path_common()
{
# Get the deepest common path.
local common_path="$(echo -n "${1:-}x" | tr -s '/')"
common_path="${common_path%x}"
shift # $1 is obviously part of $1
local path
while [ -n "${1+defined}" ]
do
path="$(echo -n "${1}x" | tr -s '/')"
path="${path%x}"
if [[ "${path%/}/" = "${common_path%/}/"* ]]
then
shift
else
new_common_path="${common_path%/*}"
[ "$new_common_path" = "$common_path" ] && return 1 # Dead end
common_path="$new_common_path"
fi
done
printf %s "$common_path"
}
Bounty geht an alle , die von der loswerden kann Duplizierung von Code doppelte Schrägstriche oder kollabieren Duplizierung von Daten zu halten $1
und die anderen Parameter, oder beide, während der Code eine vernünftige Größe zu halten und alle die Unit - Tests Erfolg:
test "$(path_common /a/b/c/d /a/b/e/f; echo x)" = /a/bx
test "$(path_common /long/names/foo /long/names/bar; echo x)" = /long/namesx
test "$(path_common / /a/b/c; echo x)" = /x
test "$(path_common a/b/c/d a/b/e/f ; echo x)" = a/bx
test "$(path_common ./a/b/c/d ./a/b/e/f; echo x)" = ./a/bx
test "$(path_common $'\n/\n/\n' $'\n/\n'; echo x)" = $'\n/\n'x
test "$(path_common --/-- --; echo x)" = '--x'
test "$(path_common '' ''; echo x)" = x
test "$(path_common /foo/bar ''; echo x)" = x
test "$(path_common /foo /fo; echo x)" = x
test "$(path_common $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n' $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'; echo x)" = $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'x
test "$(path_common /foo/bar //foo//bar//baz; echo x)" = /foo/barx
test "$(path_common foo foo; echo x)" = foox
test "$(path_common /fo /foo; echo x)" = x
Antworten:
POSIX
Um die Schrägstriche in allen Parametern zu normalisieren, verwende ich den Trick mit dem rotierenden Argument: Verschieben
$1
, transformieren und das Ergebnis am Ende der Parameterliste einfügen. Wenn Sie dies so oft tun, wie Parameter vorhanden sind, haben Sie alle Parameter transformiert und wieder in Ordnung gebracht.Für den zweiten Teil des Codes habe ich Ihre Logik so geändert, dass sie weniger verwirrend ist: Die äußere Schleife durchläuft die Parameter und die innere Schleife durchläuft die Pfadkomponenten.
for x; do … done
iteriert über die Positionsparameter, es ist eine bequeme Redewendung. Ich verwende eine POSIX-kompatible Methode, um eine Zeichenfolge mit einem Muster abzugleichen: demcase
Konstrukt.Getestet mit Strich 0.5.5.1, pdksh 5.2.14, bash 3.2.39, bash 4.1.5, ksh 93s +, zsh 4.3.10.
Randnotiz: Es scheint einen Fehler in Bash 4.1.5 zu geben (nicht in 3.2): Wenn das Fallmuster ist
"${common_path%/}"/*
, schlägt einer der Tests fehl.Bash, ksh
Wenn Sie in Bash (oder Ksh) sind, können Sie Arrays verwenden - ich verstehe nicht, warum Sie sich anscheinend auf die Positionsparameter beschränken. Hier ist eine Version, die ein Array verwendet. Ich muss zugeben, dass es nicht besonders klarer ist als die POSIX-Version, aber es vermeidet das anfängliche Mischen von n ^ 2.
Für den Slash-Normalisierungsteil verwende ich das Konstrukt ksh93-
${foo//PATTERN/REPLACEMENT}
Konstrukt, um alle Vorkommen vonPATTERN
in$foo
by zu ersetzenREPLACEMENT
. Das Muster muss+(\/)
mit einem oder mehreren Schrägstrichen übereinstimmen. unter Bashshopt -s extglob
muss in Kraft sein (äquivalent, Bash mit beginnenbash -O extglob
). Das Konstruktset ${!a[@]}
setzt die Positionsparameter auf die Liste der Indizes des Arraysa
. Dies bietet eine bequeme Möglichkeit, die Elemente des Arrays zu durchlaufen.Für den zweiten Teil habe ich die gleiche Schleifenlogik wie die POSIX-Version. Dieses Mal kann ich es verwenden,
[[ … ]]
da alle hier anvisierten Shells es unterstützen.Getestet mit Bash 3.2.39, Bash 4.1.5, ksh 93s +.
zsh
Leider fehlt zsh die
${!array[@]}
Funktion, um die ksh93-Version unverändert auszuführen. Glücklicherweise hat zsh zwei Funktionen, die den ersten Teil zum Kinderspiel machen. Sie können die Positionsparameter so indizieren, als wären sie das@
Array, sodass kein Zwischenarray verwendet werden muss. Und zsh hat ein Array-Iterationskonstrukt :"${(@)array//PATTERN/REPLACEMENT}"
Führt nacheinander die Musterersetzung für jedes Array-Element durch und wertet das Ergebnisarray aus (verwirrenderweise benötigen Sie doppelte Anführungszeichen, obwohl das Ergebnis mehrere Wörter enthält; dies ist eine Verallgemeinerung von"$@"
). Der zweite Teil ist im Wesentlichen unverändert.Testfälle
Meine Lösungen werden nur minimal getestet und kommentiert. Ich habe die Syntax Ihrer Testfälle geändert, um sie unter Shells zu analysieren, die keine
$'…'
Fehler haben, und Fehler auf bequemere Weise zu melden.quelle
Warum benutzt du nicht einfach $ 1, $ 2 .. $ 9, $ {10}, $ {11} .. und so weiter? Es ist noch trockener als das, was du versuchst :)
Mehr zur Beziehung zwischen $ number und $ @:
$ @ kann als Abkürzung für "alle Elemente eines Arrays mit allen Argumenten" betrachtet werden.
$ @ Ist also eine Art Abkürzung von $ {args [@]} (args hier ist ein 'virtuelles' Array, das alle Argumente enthält - wohlgemerkt keine echte Variable)
$ 1 ist $ {args [1]}, $ 2 ist $ {args [2]} und so weiter.
Wenn Sie [9] gedrückt haben, verwenden Sie eine geschweifte Klammer: $ {10} ist $ {args [10]}, $ {11} ist $ {args [11]} und so weiter.
Verwenden Sie indirekt ein Befehlszeilenargument
Beispiel:
quelle
${args[$i]}
.Ich denke was du willst ist
shift
quelle
Ich weiß nicht genau, warum Sie nicht nur $ 1 $ 2 usw. verwenden, sondern .. Dies kann Ihren Bedürfnissen entsprechen.
Ausgabe
set
funktioniert von allem, was darauf folgt, um $ 1, $ 2 .. etc .. zu erstellen. Dies wird natürlich die ursprünglichen Werte überschreiben, also sei dir dessen einfach bewusst.quelle
eval
manche es fürevil
... halten (vielleicht liegt es an der Schreibweise :) ... Wenneval
"schlecht" ist, ist $ {! Var} dann gleichermaßen "schlecht"? ... Für mich ist es nur ein Teil der Sprache und ein nützlicher Teil dabei ... aber ich bevorzuge definitiv $ {! Var} ...Hinweis Ich unterstütze Leerzeichen in Dateinamen.
Ich habe einen Testfall für Dateinamen mit Leerzeichen hinzugefügt und 2 Tests behoben, bei denen ein führendes / fehlte
quelle