Utilizzando | il carattere pipe di una variabile $ lo considera un altro argomento in bash; come evitarlo?


8

Ho uno script bash come questo

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

Ma dà l'errore

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

Sembra trattare i contenuti di "| sort -n"come solo un argomento passato ls.

Come posso evitarlo in modo che venga trattato come un normale comando convogliato?

Sto cercando di impostare condizionalmente il $pipedargument. Suppongo che potrei semplicemente eseguire in modo condizionale diverse versioni del comando, ma mi chiedo ancora se c'è un modo per farlo funzionare come sopra?

Risposte:


9

Hai ragione a non poter usare in |quel modo. Il motivo è che la shell ha già cercato le pipeline e le ha separate in comandi prima di effettuare la sostituzione delle variabili. Quindi, |viene trattato come un altro personaggio.

Una possibile soluzione è posizionare il carattere pipe letteralmente:

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

Nel caso in cui non si desideri una pipeline, è possibile utilizzare catcome "nop" o segnaposto:

$ cmd=cat
$ ls | $cmd

Questo metodo evita le sottigliezze di eval . Vedi anche qui .

Un approccio migliore: array

Un approccio più sofisticato userebbe le bashmatrici al posto delle stringhe semplici:

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

Il vantaggio delle matrici diventa importante non appena è necessario il comando cmdper contenere argomenti tra virgolette.


Potresti chiarire perché gli array sono necessari in caso di argomenti citati? Mi sono imbattuto in quello, ma non capisco bene perché non funziona.
anxieux,

@anxieux Una breve risposta è che una citazione, quando si trova all'interno di una stringa di shell, perde tutto il suo potere sintattico per raggruppare le parole e viene invece trattata come qualsiasi altro personaggio. Per una discussione più lunga ed eccellente di questo problema, vedi: Sto cercando di inserire un comando in una variabile, ma i casi complessi falliscono sempre! .
Giovanni 1024

5

Puoi evalusare il comando:

eval "ls $pipedargument"

o meglio definire funzioni come:

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

e in seguito chiamalo con gli argomenti desiderati:

sorted ls /tmp

Un'altra opzione sarebbe quella di definire un alias: alias ls='ls | sort -n'
thiagowfx

0

Vorrei usare una funzione per questo. Qualcosa di simile a:

### 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.