Menggunakan data yang dibaca dari sebuah pipa alih-alih dari file dalam opsi perintah

18

Per definisi manusia, perintah ini mendapat input dari file.

$ command -r FILENAME

Misalkan itu FILENAMEadalah file yang berisi daftar nama file, seperti yang dihasilkan menggunakan ls > FILENAME.

Bagaimana saya bisa, sebaliknya, memberi makan perintah dengan hasil lslangsung? Di kepalaku sesuatu seperti ini seharusnya dimungkinkan:

$ ls | command -r

Tapi tidak, output dari lstidak ketagihan sebagai argumen. Keluaran:

Usage: command -r FILENAME
error: -r option requires an argument

Bagaimana saya bisa mendapatkan efek yang diinginkan?

Paolo
sumber
Lebih banyak jawaban tentang ini dalam pertanyaan terkait: Bagaimana cara mengirimkan string ke perintah yang mengharapkan file?
ilkkachu

Jawaban:

31

Ini tergantung pada perintah. Beberapa perintah yang membaca dari file berharap bahwa file tersebut adalah file biasa, yang ukurannya diketahui sebelumnya, dan yang dapat dibaca dari posisi apa pun dan diputar ulang. Ini tidak mungkin jika isi file adalah daftar nama file: maka perintah mungkin akan puas dengan sebuah pipa yang hanya akan dibaca secara berurutan dari awal hingga selesai. Ada beberapa cara untuk memberi makan data melalui pipa ke perintah yang mengharapkan nama file.

  • Banyak perintah memperlakukan -sebagai nama khusus, artinya membaca dari input standar daripada membuka file. Ini adalah konvensi, bukan kewajiban.

    ls | command -r -
  • Banyak varian unix yang menyediakan file khusus untuk /devmendeskripsi deskriptor standar. Jika /dev/stdinada, membukanya dan membaca darinya setara dengan membaca dari input standar; demikian juga /dev/fd/0jika itu ada.

    ls | command -r /dev/stdin
    ls | command -r /dev/fd/0
  • Jika shell Anda adalah ksh, bash atau zsh, Anda dapat membuat shell menangani urusan mengalokasikan beberapa deskriptor file. Keuntungan utama dari metode ini adalah tidak terikat dengan input standar, sehingga Anda dapat menggunakan input standar untuk hal lain, dan Anda dapat menggunakannya lebih dari sekali.

    command -r <(ls)
  • Jika perintah mengharapkan nama memiliki bentuk tertentu (biasanya ekstensi tertentu), Anda dapat mencoba membodohinya dengan tautan simbolis.

    ln -s /dev/fd/0 list.foo
    ls | command -r list.foo

    Atau Anda bisa menggunakan pipa bernama.

    mkfifo list.foo
    ls >list.foo &
    command -r list.foo

Perhatikan bahwa membuat daftar file dengan lsmasalah karena lscenderung untuk mengurai nama file ketika mengandung karakter yang tidak diinginkan. printf '%s\n' *lebih dapat diandalkan - itu akan mencetak setiap byte secara harfiah dalam nama file. Nama file yang mengandung baris baru masih akan menyebabkan masalah, tetapi itu tidak dapat dihindari jika perintah mengharapkan daftar nama file yang dipisahkan oleh baris baru.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
+1 untuk menghitung semua kemungkinan. Substitusi proses IMO adalah jawaban yang tepat untuk situasi ini.
glenn jackman
7

Harus:

ls | xargs -n 1 command -r

Edit: untuk nama dengan spasi kosong:

ls | xargs -d '\n' -n 1 command -r
ghm1014
sumber
Ini bisa menjadi masalah jika commandpercaya ia memiliki semua nama file yang dibutuhkan pada baris perintah sekaligus. Beberapa versi xargs akan memberikan commandbeberapa nama file (10, menurut saya) sekaligus. Sepertinya GNU xargs memberikan semuanya sekaligus.
Bruce Ediger
2

Sebenarnya, satu-satunya solusi andal yang saya tahu yang dapat menangani semua nama file, termasuk yang memiliki baris baru di dalamnya, adalah:

find . -maxdepth 1 -print0 | xargs -n 1 -0 command -r

Satu-satunya karakter yang tidak diperbolehkan dalam nama file dalam kasus ini adalah karakter nol, yang tidak diperbolehkan dalam nama file.

Linus Swälas
sumber
1

Banyak perintah menerima -sebagai "nama file" yang berarti "menggunakan input standar", tetapi konvensi ini jauh dari universal. Baca halaman manual.

dmckee
sumber
1

Ini harus berfungsi untuk tujuan Anda: ls | command -r /dev/stdin

alex
sumber