Menggunakan | karakter pipa dari variabel $ membuatnya diperlakukan sebagai argumen lain di bash; bagaimana cara menghindarinya?

8

Saya memiliki skrip bash seperti ini

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

Tapi itu memberi kesalahan

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

Tampaknya memperlakukan konten "| sort -n"hanya sebagai argumen ls.

Bagaimana saya bisa menghindarinya sehingga diperlakukan sebagai perintah pipa biasa?

Saya mencoba mengatur $pipedargument. Saya kira saya hanya bisa menjalankan versi berbeda dari perintah tetapi masih bertanya-tanya apakah ada cara untuk membuat pekerjaan ini seperti di atas?

laggingreflex
sumber

Jawaban:

9

Anda benar bahwa Anda tidak dapat menggunakan |cara itu. Alasannya adalah bahwa shell sudah mencari pipa dan memisahkannya menjadi perintah sebelum melakukan substitusi variabel. Karenanya, |diperlakukan hanya sebagai karakter lain.

Satu kemungkinan penyelesaian adalah menempatkan karakter pipa secara harfiah:

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

Jika Anda tidak menginginkan saluran pipa, Anda dapat menggunakan catsebagai "nop" atau placeholder:

$ cmd=cat
$ ls | $cmd

Metode ini menghindari seluk - beluk eval . Lihat juga di sini .

Pendekatan yang lebih baik: array

Pendekatan yang lebih canggih akan menggunakan basharray sebagai ganti string:

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

Keuntungan array menjadi penting segera setelah Anda membutuhkan perintah cmduntuk memuat argumen yang dikutip.

John1024
sumber
Bisakah Anda mengklarifikasi mengapa array diperlukan jika ada argumen yang dikutip? Saya mengalami itu, tetapi tidak mengerti mengapa itu tidak berhasil.
anxieux
@anxieux Jawaban singkatnya adalah bahwa kutipan, ketika di dalam string shell, kehilangan semua kekuatan sintaksisnya untuk mengelompokkan kata-kata dan malah diperlakukan seperti karakter lainnya. Untuk diskusi yang lebih lama dan luar biasa tentang masalah ini, lihat: Saya mencoba untuk menempatkan perintah dalam variabel, tetapi kasus kompleks selalu gagal! .
John1024
5

Anda dapat evalmenggunakan perintah:

eval "ls $pipedargument"

atau lebih tepatnya mendefinisikan fungsi seperti:

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

dan kemudian menyebutnya dengan argumen yang diinginkan:

sorted ls /tmp
jimmij
sumber
Pilihan lain adalah mendefinisikan alias:alias ls='ls | sort -n'
thiagowfx
0

Saya akan menggunakan fungsi untuk ini. Sesuatu seperti:

### 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
sumber