Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Äquivalent für „$_“ innerhalb eines Befehls?

1 view
Skip to first unread message

Tim Landscheidt

unread,
Aug 14, 2022, 9:44:23 AM8/14/22
to
Moin,

als Fan von „Don’t repeat yourself“ benutze ich gerne „$_“
in GNU bash à la:

| diff file1.ext file2.txt && rm -i "$_"

Was mir fehlt, ist ein Äquivalent innerhalb eines Befehls,
beispielsweise in:

| diff file.txt /tmp/file.txt

sollte ich „file.txt“ nicht wiederholen müssen oder in:

| psql -f file.sql -o file.txt

nicht „file“.

Das ist mit einer Variablen (und gegebenenfalls einer Sub-
shell für die Kapselung) kein Problem:

| (f=file.txt && diff "$f" /tmp/"$f")
| (f=file.sql && psql -f "$f" -o "${f%.sql}.txt")

Auch die Tab-Vervollständigung funktioniert. Der Nachteil
ist, dass ich nach dem Eintippen des initialen „diff
file.txt“ oder „psql -f file.sql“ erst einmal den kompletten
Befehl umbauen muss; schöner wäre, wenn etwas à la:

| diff file.txt "/tmp/${ARGV[-1]}"

oder:

| psql -f file.sql -o "${ARGV[-2]%.sql}.txt"

funktionieren würde.

Gibt es da eine Möglichkeit, die ich überlesen habe?

Tim

Axel Reichert

unread,
Aug 14, 2022, 10:25:57 AM8/14/22
to
Tim Landscheidt <t...@tim-landscheidt.de> writes:

> beispielsweise in:
>
> | diff file.txt /tmp/file.txt
>
> sollte ich „file.txt“ nicht wiederholen müssen

Geht, wenn du in deiner bash nicht "history expansion" a la "csh"
abgeklemmt hast. Denn dann wird (mit ueblicher Numerierung der
Argumente, es gibt auch "^", "$" oder "*" und noch mehr)

echo foo bar baz !#:2

zu

echo foo bar baz bar

expandiert und gibt

foo bar baz bar

aus. "man bash", "HISTORY EXPANSION". (-:

Tschoe!

Axel

Christian Weisgerber

unread,
Aug 14, 2022, 11:30:05 AM8/14/22
to
On 2022-08-14, Tim Landscheidt <t...@tim-landscheidt.de> wrote:

> als Fan von „Don’t repeat yourself“ benutze ich gerne „$_“
> in GNU bash à la:
>
>| diff file1.ext file2.txt && rm -i "$_"
>
> Was mir fehlt, ist ein Äquivalent innerhalb eines Befehls,
> beispielsweise in:
>
>| diff file.txt /tmp/file.txt
>
> sollte ich „file.txt“ nicht wiederholen müssen

Das geht mit der History Expansion. !# bezeichnet die aktuelle
Zeile. Beispiel:

$ diff file.txt /tmp/!#:1

--
Christian "naddy" Weisgerber na...@mips.inka.de

Tim Landscheidt

unread,
Aug 15, 2022, 4:20:58 AM8/15/22
to
Axel Reichert <ma...@axel-reichert.de> wrote:

>> beispielsweise in:

>> | diff file.txt /tmp/file.txt

>> sollte ich „file.txt“ nicht wiederholen müssen

> Geht, wenn du in deiner bash nicht "history expansion" a la "csh"
> abgeklemmt hast. Denn dann wird (mit ueblicher Numerierung der
> Argumente, es gibt auch "^", "$" oder "*" und noch mehr)

> echo foo bar baz !#:2

> zu

> echo foo bar baz bar

> expandiert und gibt

> foo bar baz bar

> aus. "man bash", "HISTORY EXPANSION". (-:

Danke, auch an Christian. Auch wenn es mit meiner Unwissen-
heit nichts zu tun hat, hatte ich tatsächlich „set +H“ in
meiner ~/.bashrc, da ich (zu) viel Zeit vergeblich damit
verbracht hatte zu verstehen, warum man „!“ in doppelten An-
führungszeichen escapen kann, dann aber der Backslash mit
ausgegeben wird:

| [tim@vagabond ~]$ echo "Du bist $USER!1"
| bash: !1: event not found
| [tim@vagabond ~]$ echo "Du bist $USER\!1"
| Du bist tim\!1
| [tim@vagabond ~]$

Wenn ich Texte oder auch nur Dateinamen in eine (interakti-
ve) Befehlszeile kopierte, führte das immer zu maximaler
Verwirrung.

Hmmm. Einmal sehen, ob ich mich an „set -H“ gewöhnen kann.

Tim

Axel Reichert

unread,
Aug 15, 2022, 4:43:38 AM8/15/22
to
Tim Landscheidt <t...@tim-landscheidt.de> writes:

> da ich (zu) viel Zeit vergeblich damit verbracht hatte zu verstehen,
> warum man „!“ in doppelten An- führungszeichen escapen kann, dann aber
> der Backslash mit ausgegeben wird:
>
> | [tim@vagabond ~]$ echo "Du bist $USER!1"
> | bash: !1: event not found
> | [tim@vagabond ~]$ echo "Du bist $USER\!1"
> | Du bist tim\!1
> | [tim@vagabond ~]$
>
> Wenn ich Texte oder auch nur Dateinamen in eine (interakti-
> ve) Befehlszeile kopierte, führte das immer zu maximaler
> Verwirrung.

Gelegenheit, die Frau von Donald Knuth zu paraphrasieren:

Don't use exclamation marks in your output, Tim.

Oder gleich den Pratchett:

Multiple exclamation marks are a sure sign of a diseased mind.

(-;

> Hmmm. Einmal sehen, ob ich mich an „set -H“ gewöhnen kann.

Ist nicht soo schlimm, wenn man Frau Knuth beherzigt. Ausnahme:
Negationen in z. B. awk. Hatte zu tcsh-Zeiten einige nette "history
expansion"-Mechanismen in mein Repertoire uebernommen.

Tschoe!

Axel

Tim Landscheidt

unread,
Aug 15, 2022, 6:21:06 AM8/15/22
to
Axel Reichert <ma...@axel-reichert.de> wrote:

> […]

>> Hmmm. Einmal sehen, ob ich mich an „set -H“ gewöhnen kann.

> Ist nicht soo schlimm, wenn man Frau Knuth beherzigt. Ausnahme:
> Negationen in z. B. awk. Hatte zu tcsh-Zeiten einige nette "history
> expansion"-Mechanismen in mein Repertoire uebernommen.

Ach, ja, das war das Hauptproblem! Ich benutze kaum Ausrufe-
zeichen, aber häufig einfache Anführungszeichen, und habe
daher in Perl-Scripts/-Onelinern nicht selten Konstrukte à
la „q!eine 'Zeichenkette'!“. Wenn ich Teile davon (oder auch
reguläre Ausdrücke mit „!“) in einer interaktiven Shell ent-
wickeln/debuggen wollte, flog mir das gelegentlich um die
Ohren. Hmmm. Hmmm. Hmmm.

Tim

Tim Landscheidt

unread,
Aug 23, 2022, 5:08:36 AM8/23/22
to
Falls es jemanden interessiert: Nach etwas mehr Herumspielen
habe ich jetzt die beiden weiteren großen Probleme wiederer-
kannt, die mich damals zu „set +H“ verleiteten:

1. Die History wird „umgeschrieben“:

| [tim@vagabond ~]$ echo Test && echo !#:1
| echo Test && echo Test
| Test
| Test
| [tim@vagabond ~]$ echo Test && echo Test

(An dem zweiten Prompt einmal <up> gedrückt.) Das heißt,
wenn ich jetzt „Test“ durch „"Kein Test"“ ersetzen will,
muss ich das zweite „Test“ wieder durch „!#:1“ ersetzen.

2. Die Expansion findet rein auf textlicher Ebene statt:

| [tim@vagabond ~]$ echo "$RANDOM" && echo !#:1
| echo "$RANDOM" && echo "$RANDOM"
| 18183
| 808
| [tim@vagabond ~]$

Das ist meistens nicht das, was ich will, und tendentiell
gefährlich, wenn in einem „word“ etwas geschieht, was nur
einmal ausgeführt werden darf oder bei jedem Aufruf ein
anderes Ergebnis erzeugt.

Daher werde ich „set +H“ zwar aus meiner ~/.bashrc nehmen,
um nicht überrascht zu werden, wenn ich auf anderen Systemen
arbeite, aber für mein ursprüngliches Problem dann wohl doch
bei Mustern à la „(f=file.txt && diff "$f" "/tmp/$f" && …)“
bleiben.

Besten Dank für alle Hinweise,
Tim

Axel Reichert

unread,
Aug 28, 2022, 4:42:32 AM8/28/22
to
Tim Landscheidt <t...@tim-landscheidt.de> writes:

> Falls es jemanden interessiert: Nach etwas mehr Herumspielen
> habe ich jetzt die beiden weiteren großen Probleme wiederer-
> kannt, die mich damals zu „set +H“ verleiteten:
>
> 1. Die History wird „umgeschrieben“:
>
> | [tim@vagabond ~]$ echo Test && echo !#:1
> | echo Test && echo Test
> | Test
> | Test
> | [tim@vagabond ~]$ echo Test && echo Test
>
> (An dem zweiten Prompt einmal <up> gedrückt.) Das heißt,
> wenn ich jetzt „Test“ durch „"Kein Test"“ ersetzen will,
> muss ich das zweite „Test“ wieder durch „!#:1“ ersetzen.

Ja. Das hatte mich vor Urzeiten (koennte noch tcsh gewesen sein) auch
gestoert, und ich erinnere mich dunkel, dass man steuern konnte, dass
ein Kommando in noch nicht "history-expandierter" Form in der
history-Datei abgelegt wurde, die dann Schweinkram wie ^falsch^flasch
enthielt. Heutzutage wuerde ich spaetestens an dieser Stelle ueber
Skripte nachdenken, aber mit tcsh vermeidet man ja besser Skripting ...

man bash liefert aber keine verdaechtigen Shell-Variablen/Optionen,
wahrscheinlich also echt tcsh.

Tschoe!

Axel


0 new messages