Verwenden von | Durch das Pipe-Zeichen einer $ -Variablen wird es als ein weiteres Argument in bash behandelt. wie kann man dem entkommen?

8

Ich habe so ein Bash-Skript

export pipedargument="| sort -n"
ls $pipedargument

Aber es gibt den Fehler

ls: |: No such file or directory
ls: sort: No such file or directory

Es scheint den Inhalt von "| sort -n"nur als ein Argument zu behandeln, an das weitergegeben wird ls.

Wie kann ich dem entkommen, damit es als regulärer Pipeline-Befehl behandelt wird?

Ich versuche das bedingt einzustellen $pipedargument. Ich denke, ich könnte nur verschiedene Versionen des Befehls unter bestimmten Bedingungen ausführen, frage mich aber immer noch, ob es eine Möglichkeit gibt, dies wie oben beschrieben zu machen?

Laggingreflex
quelle

Antworten:

9

Sie haben Recht, dass Sie so nicht verwenden |können. Der Grund dafür ist, dass die Shell bereits nach Pipelines gesucht und diese in Befehle unterteilt hat, bevor die Variablensubstitution durchgeführt wird. Daher |wird nur ein weiteres Zeichen behandelt.

Eine mögliche Problemumgehung besteht darin, das Pipe-Zeichen wörtlich zu platzieren:

$ cmd="sort -n"
$ ls | $cmd

Falls Sie keine Pipeline möchten, können Sie diese catals "NOP" oder Platzhalter verwenden:

$ cmd=cat
$ ls | $cmd

Diese Methode vermeidet die Feinheiten der Bewertung . Siehe auch hier .

Ein besserer Ansatz: Arrays

Ein ausgefeilterer Ansatz würde bashArrays anstelle von einfachen Zeichenfolgen verwenden:

$ cmd=(sort -n)
$ ls | "${cmd[@]}"

Der Vorteil von Arrays wird wichtig, sobald der Befehl cmdAnführungszeichen enthält.

John1024
quelle
Können Sie klarstellen, warum Arrays bei Argumenten in Anführungszeichen benötigt werden? Ich bin darauf gestoßen, verstehe aber nicht ganz, warum es nicht funktioniert.
anxieux
@anxieux Eine kurze Antwort lautet, dass ein Zitat in einer Shell-Zeichenfolge seine gesamte syntaktische Kraft zum Gruppieren von Wörtern verliert und stattdessen wie jedes andere Zeichen behandelt wird. Eine längere und ausgezeichnete Diskussion dieses Problems finden Sie unter: Ich versuche, einen Befehl in eine Variable einzufügen, aber die komplexen Fälle schlagen immer fehl! .
John1024
5

Sie können evalden Befehl verwenden:

eval "ls $pipedargument"

oder noch besser definieren Funktion wie:

sorted() { "$@" | sort -n; }

und später mit den gewünschten Argumenten aufrufen:

sorted ls /tmp
jimmij
quelle
Eine andere Möglichkeit wäre, einen Alias ​​zu definieren:alias ls='ls | sort -n'
thiagowfx
0

Ich würde dafür eine Funktion verwenden. Etwas wie:

### usage pipedargument cmd args ###

pipedargument()
{
    sort -n <<< "$( "$@" )"
}

$ pipedargument /sbin/ifconfig eth0
      RX bytes:5904986765 (5.4 GiB)  TX bytes:714370767 (681.2 MiB)
      RX packets:5981427 errors:0 dropped:0 overruns:0 frame:0
      TX packets:4403989 errors:0 dropped:0 overruns:0 carrier:0
      UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
      collisions:0 txqueuelen:1000 
      inet addr:XXX.XXX.X.XX  Bcast:XXX.XXX.X.XXX  Mask:255.255.255.0
      inet6 addr: xx00::0x0x:00xx:xx0:000/00 Scope:Link
eth0      Link encap:Ethernet  HWaddr 0x:0x:00:x0:00:00
Grepper
quelle