Kann die Befehlssubstitution in der Variablensubstitution verschachtelt werden?

10

Ich möchte die Variablensubstitution für eine bestimmte Zeichenfolge verwenden, auf die ich über einen Befehl zugreife. Wenn ich beispielsweise etwas in meine Zwischenablage kopiere, kann ich wie folgt darauf zugreifen.

$ xclip -o -selection clipboard
Here's a string I just copied.

Wenn ich es einer Variablen zuordne, kann ich es durch Variablen ersetzen.

$ var=$(xclip -o -selection clipboard)
$ echo $var
Here's a string I just copied.
$ echo ${var/copi/knott}
Here's a string I just knotted.

Gibt es jedoch eine Möglichkeit, eine Variablensubstitution durchzuführen, ohne sie einer Variablen zuzuweisen? Konzeptionell so etwas.

$ echo ${$(xclip -o -selection clipboard)/copi/knott}
bash: ${$(xclip -o -selection clipboard)/copi/knott}: bad substitution

Diese Syntax schlägt fehl, da es varsich um einen Variablennamen und nicht um eine Zeichenfolge handeln sollte.

Sparhawk
quelle

Antworten:

6

Nein, das kannst du nicht. bashund die meisten anderen Shells (außer zsh) erlauben keine verschachtelte Substitution.

Mit zshkönnen Sie verschachtelte Ersetzungen durchführen :

$ echo ${$(echo 123)/123/456}   
456
cuonglm
quelle
Ich werde diese Antwort akzeptieren, da sie einige Indizien dafür liefert, dass dies in nicht möglich ist bash. (Und drängt mich erneut in Richtung Migration zsh.)
Sparhawk
2

Ja, das kannst du machen - irgendwie. Es ist wirklich nicht schön. Es ist eher inline als verschachtelt. Das Problem ist, dass Sie den Wert des zu erweiternden Parameters bearbeiten müssen. Wenn dieser Parameter keinen Wert hat, werden Sie nicht viel tun. Sie können den Wert also beim Erweitern zuweisen und es handelt sich kaum um eine Verknüpfung.

v=; echo "${v:=${0##*["$0${v:=$(xsel -bo)}"]}${v/copi/knott}}"

Ich benutze die $0Parametererweiterung innerhalb der Kette, um die Zuordnung zu verbergen . Es weist den Wert der Variable innerhalb einer verschachtelten Zuweisungserweiterung zu. Das Äußere hat Vorrang - aber weil es sich nur auf das ausdehnt, was das Innere tut, ist es schwer zu sagen. Wenn wir jedoch die innere Erweiterung zum Schweigen bringen und sie dann ändern, können Sie das bekommen, was Sie wollen. Nachdem Sie Ihre Zeichenfolge in meine Zwischenablage kopiert haben (ich habe sie nicht xclip- nur xsel), wird sie gedruckt:

Here's a string I just knotted.

Es ist jedoch etwas klarer, was los ist, wenn Sie $0weglassen:

v=; echo "${v:=${v:=$(xsel -bo)}${v/copi/knott}}"

Das druckt:

Here's a string I just copied.  Here's a string I just knotted.

... weil die innere Zuordnung vor der Änderung erfolgt, die äußere Zuweisung jedoch, wie bereits erwähnt, Vorrang hat - und sich sowohl auf die Erweiterung der inneren Zuordnung als auch auf die modifizierte innere Erweiterung ausdehnt .

Natürlich funktioniert nichts davon, wenn der Zielparameter bereits zugewiesen ist - Sie können dies also nur dann sicher tun, wenn Sie die Variable zuerst leeren ... was ehrlich gesagt wahrscheinlich der bequemste Zeitpunkt ist, um sie schließlich zuzuweisen .

mikeserv
quelle
+1 für die Problemumgehung, obwohl es, wie Sie sagen, eine Problemumgehung ist, die wahrscheinlich schlimmer ist als das Zuweisen einer Variablen!
Sparhawk
@ Sparhawk - ja, definitiv schlimmer. Und daran ist wirklich nichts auszusetzen - es gibt nicht viel zu gewinnen, außer Unsicherheit. Sie könnten sich eine aliasIndirektion einfallen lassen , um es ein wenig bequemer zu machen - aber wenn es sich für Sie lohnt, sollten Sie eine Funktion einrichten, um sicheres Zitieren zu handhaben und etwas mit evaletwas Ähnlichem zu tun . w / eval- Wenn Sie die ersten Zeichen der Ausgabemenge des Befehlssubs auf eine funktionsfähige Erweiterungssyntax bringen können, können Sie wahrscheinlich viel einfacher werden. Ich weiß, dass so etwas einfach wäre w xsel- - es braucht stdin - aber xsel?
Mikeserv
@Sparhawk - Ich weiß übrigens nur, wie man das macht, weil es in einigen Situationen nützlich sein kann - wie bei Eingabeaufforderungen oder Erweiterungen für Eingabeaufforderungen -, in denen Sie keine aktuelle Shell-Zuweisung erhalten können, um sie anderweitig anzuwenden.
Mikeserv
1

Wenn Sie keine Variable erstellen möchten, gibt es andere Möglichkeiten, eine Zeichenfolgenersetzung durchzuführen:

$ echo $(xclip -o -selection clipboard | sed 's/copi/knott/')
Here's a string I just knotted.
John1024
quelle
Danke, ich wusste, dass ich sedstattdessen verwenden könnte, aber es sollte eher eine allgemeine Frage zum Verschachteln von Substitutionen sein.
Sparhawk
@ Parhawk Meines Wissens kann man keine Variablensubstitution durchführen, ohne eine Variable zu haben.
John1024
Okay, das ist dann wahrscheinlich die Antwort. Ich werde die Frage einige Tage offen lassen, um zu sehen, ob jemand eine Antwort hat, auf die verwiesen wird, und diese dann anderweitig akzeptieren. Vielen Dank.
Sparhawk
@ Sparhawk Sehr gut.
John1024
+1, aber ich werde eine andere Antwort akzeptieren , da sie etwas konkretere Indizien dafür liefert, dass sie in Bash nicht funktioniert.
Sparhawk