Wird die Parametererweiterung auf $ @ von der sh-Shell nicht unterstützt?

8

Ich habe eine Antwort auf eine Frage zu AU gepostet und festgestellt, dass die Parametererweiterung bei $@nicht mit der shShell funktioniert :

<infile xargs -d'\n' sh -c 'echo "${@%%/*}"' _

aber es funktioniert gut in bash. Ist dies das erwartete Verhalten der shShell und wie kann ich dort eine Erweiterung durchführen?

Außerdem weiß ich, dass ich mit der -n1Option xargsnur jeweils eine Zeile an den Befehl übergeben kann, aber ich war daran interessiert, ob shFolgendes erweitert werden kann $@:

<infile xargs -d'\n' -n1 sh -c 'echo "${0%%/*}"'

infile enthält:

A1 /B1/C1
A 2/B2/C2
A3/B3/C3
αғsнιη
quelle

Antworten:

12

Ja, Bindestrich scheint hier weniger als nützlich zu sein. Obwohl es nicht Schuld ist, streng genommen, wie ${@%...}ist nicht spezifiziert durch POSIX :

Die folgenden vier Varianten der Parametererweiterung ermöglichen die Verarbeitung von Teilzeichenfolgen. [...] Wenn der Parameter ' #', ' *' oder ' @' ist, ist das Ergebnis der Erweiterung nicht angegeben.

Es ist jedoch seltsam, es scheint, dass wenn eine solche Erweiterung das Ende eines Positionsparameters ändert, die folgenden gelöscht werden. Aber nicht, wenn es das Ende nicht wirklich verändert:

$ dash -c 'set -- foo bar; printf "<%s>\n" "${@%o}";'
<fo>
$ dash -c 'set -- foo bar; printf "<%s>\n" "${@%x}";'
<foo>
<bar>
$ dash -c 'set -- foo bar doo; printf "<%s>\n" "${@%r}";'
<foo>
<ba>

Bash, ksh und Zsh scheinen alle Positionsparameter unabhängig zu handhaben "${@#...}"und zu "${@%...}"verarbeiten, was als nützlich erscheint.

Ich nehme an, die offensichtliche Problemumgehung dashbesteht darin, die Änderung Argument für Argument zu machen:

for x in "$@"; do echo "${x%%/*}"; done

Für das, was es wert ist, $*variiert das Verhalten der Erweiterungen zum Entfernen von Präfixen / Suffixen auch zwischen Shells. Bash und ksh scheinen zuerst die Parameter zu ändern und sie danach zu verbinden, während Zsh und dash zuerst die Parameter verbinden und die verkettete Zeichenfolge ändern:

$ zsh -c 'set -- ax bx; printf "<%s>\n" "${*%%x*}";'
<a>
$ bash -c 'set -- ax bx; printf "<%s>\n" "${*%%x*}";'
<a b>
ilkkachu
quelle
Sounds shdenkt, dass dies $@ein einzelner Parameter für die gesamte Datei ist (oder bei Überschreitung von ARG_MAX in mehrere Parameter zerfällt) und das einzige Argument erweitert.
αғsнιη
1
Beachten Sie auch, dass pdksh und Derivate Ihnen einen Bad substitutionFehler in diesem Code geben. Denn ${*%pattern}Sie sehen einige Variationen im Verhalten in Dingen wie"$shell" -c 'printf "<%s>\n" "${*%x*}"' sh ax by
Stéphane Chazelas
1
@ αғsнιη, so einfach ist das nicht. Beachten Sie das zweite Beispiel, bei dem die Erweiterung die Positionsparameter als separate Wörter belässt. Und ich glaube nicht ARG_MAX, dass die Verarbeitung innerhalb der Shell erfolgt.
Ilkkachu