Bagaimana input standar dari satu program dapat diteruskan sebagai argumen ke yang lain?

17

Katakanlah ada program, yang membutuhkan dua argumen; file input dan file output.

Bagaimana jika saya tidak ingin menyimpan file output ini ke disk, melainkan meneruskannya langsung ke stdinprogram lain. Apakah ada cara untuk mencapai ini?

Banyak perintah yang saya temui di Linux memberikan opsi untuk meneruskan '-' sebagai argumen file output, yang melakukan apa yang saya tentukan di atas. Apakah ini karena melewatkan stdinprogram sebagai argumen tidak mungkin? Jika ya, bagaimana kita melakukannya?

Contoh bagaimana saya akan menggunakan gambar ini adalah:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" stdin(echo)

Shell yang saya gunakan adalah bash.

Dziugas
sumber
1
cat <file | cmd /dev/fd/0bekerja pada sebagian besar unix.
mikeserv
Tidak bekerja untukku. Mencobanya dengan: cat < README.txt | cp /dev/fd/0. Dikatakancp: missing destination file operand after ‘/dev/fd/0’ Try 'cp --help' for more information.
Dziugas
1
program input-file /dev/stdout | another-program? Perhatikan juga bahwa echotidak membaca apa pun dari stdin.
yaegashi
1
@ Dziugas - tentu saja tidak - Anda tidak dapat cpfile di mana pun. echo 1 2 3| cp /dev/fd/0 /dev/ttyakan dicetak 1 2 3. Dan omong-omong, /dev/fd/[num]lebih cenderung bekerja daripada /dev/std(in|out|err)dalam kebanyakan kasus. Lihat Portabilitas Link Deskriptor File tentang apa yang dapat Anda harapkan untuk bekerja di mana.
mikeserv
1
Program UNIX yang baik akan menulis ke output standar dan menyerahkannya kepada pengguna untuk memutuskan apakah mereka ingin mengarahkan ulang ke file atau pipa ke perintah lain.
Jorge Bucaran

Jawaban:

13

Jika program mendukung penulisan ke deskriptor file apa pun meskipun tidak dapat dicari, Anda dapat menggunakan /dev/stdoutsebagai file output. Ini adalah tautan ke /proc/self/fd/1sistem saya. Deskriptor file 1 adalah stdout.

TiCPU
sumber
Ini memecahkan pertanyaan saya. Jadi apakah tidak ada cara untuk melakukannya ketika program perlu mencari?
Dziugas
3
Jika Anda mencoba untuk mencegah akses disk, Anda dapat menulis file di / dev / shm /, namun, jika Anda tidak ingin ada file di sistem file, maka sejauh yang saya tahu, tidak ada cara untuk mencari di sebuah pipa. Mencari maju berarti ia harus buffering semua dalam memori sampai mencapai titik itu ke depan, dan mencari mundur berarti memiliki buffering semua dalam memori.
TiCPU
pdftotextseperti banyak (tetapi tidak semua) utilitas lain mendukung -untuk itu juga (yang akan bekerja bahkan pada sistem yang tidak mendukung / dev / stdout, atau di mana / dev / stdout tidak berfungsi seperti yang diharapkan seperti di Linux di mana stdout tidak sebuah pipa). pdftotext file.pdf - | wc -c
Stéphane Chazelas
11

Dari pdftotexthalaman manual:

Jika file teks ´- ', teks dikirim ke stdout.

Jadi dalam hal ini yang Anda butuhkan adalah:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" -

Atau jika Anda ingin mengirim pipa ini ke STDIN dari program lain:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" - | another_prog

Menggunakan -sebagai pengganti nama file adalah konvensi yang diikuti banyak utilitas (termasuk pdftotext) ketika kita ingin input dari STDIN atau output ke STDOUT. Namun tidak semua utilitas mengikuti konvensi ini. Dalam hal ini cara idiomatis untuk melakukan ini di bash adalah dengan menggunakan proses substitusi :

my_utility "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" >( cat )

Di sini >( )sebagian besar berperilaku seperti file yang diteruskan my_utility, tetapi alih-alih menjadi file nyata, aliran dialirkan ke stdin dari proses yang terkandung, yaitu cat. Jadi di sini, teks pada akhirnya harus keluar sesuai kebutuhan.

Penggunaan lonceng alarm UUOCcat hampir selalu mematikan di forum seperti ini. Saya berpendapat bahwa jika utilitas tidak mendukung , maka ini adalah penggunaan yang bermanfaat , meskipun jika ada cara untuk melakukan proses substitusi ini tanpa , maka saya semua telinga ;-).-catcat

Namun, jika (seperti yang dinyatakan pertanyaan) tujuan akhir dari aliran adalah STDIN dari program lain, maka catdapat dihilangkan:

my_utility "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" >( another_prog )
Trauma Digital
sumber
2
Dan biarkan saya mundur sekali lagi: jika prog2menulis ke stdout, lebih baik daripada , karena formulir menunggu untuk selesai (yaitu, sebelum shell mengeluarkan prompt berikutnya atau melanjutkan ke perintah berikutnya (misalnya, setelah atau )), sedangkan -bentuk tanpa menunggu hanya untuk menyelesaikan. Selain itu, setelah formulir, adalah status keluar dari , sedangkan, di lain, adalah status keluar dari . (Anda membayar uang Anda dan mengambil pilihan Anda.)prog1 input_file >( cat ) | prog2prog1 input_file >( prog2 )catprog2;&&catprog1cat$?prog2$?prog1
Scott
4

Jika shell Anda mendukungnya, cara paling sederhana untuk melakukan manipulasi seperti itu adalah dengan menggunakan substitusi proses : <(…)dan >(…). Ini bekerja di bash, zsh dan ksh dan mungkin shell lainnya. Sebagai contoh:

$ sort <(printf "b\nc\na\n")
a
b
c
$ ls
foo
$ cp <(find . -name foo) bar
$ ls
bar  foo

Namun, ini tidak akan membantu dalam contoh yang Anda nyatakan karena pdftotextakan menyimpan dalam file teks. Meskipun pilihan terbaik Anda (selain dari yang sudah jelas digunakan -) adalah untuk digunakan /dev/stdoutseperti yang disarankan oleh @TiCPU, Anda juga bisa menggunakan fitur shell lainnya. Konstruk !:Nmengacu pada argumen ke-N dari perintah sebelumnya. Karena itu, Anda dapat melakukan:

$ pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf"  out.txt
$ cat !:2
terdon
sumber
1
Meskipun saya setuju bahwa cat <()ini dapat berguna dalam beberapa situasi, namun dalam skenario ini tidak berfungsi sama sekali. Masalahnya (sangat buruk dijelaskan oleh OP, saya harus akui) adalah bahwa pdftotextdibutuhkan dua argumen: file input dan file output . Jika argumen kedua hilang maka tidak menghasilkan apa-apa, demikian cat <(pdftotext "file.pdf")juga tidak akan mengembalikan apa pun. Seseorang dapat menipu pdftotextperintah dengan memberi >(cat)sebagai argumen kedua seperti Digital Trauma yang dijawab, tetapi cat <()tidak ada gunanya di sini. Jelas pdftotextkalau-kalau yang terbaik hanya digunakan -sebagai nama file output.
jimmij
1
@Scott Bagaimana jawaban saya UUOC? Bagaimana Anda akan melakukan proses substitusi ini tanpa kucing? >( )akan secara efektif menyalurkan aliran ke proses apa pun yang ada di dalam - jadi kami benar-benar perlu di catsini untuk menampilkan aliran itu. Biasanya kita harus dapat melakukan sesuatu seperti pdftotext input.pdf -, tetapi ternyata pdftotexttidak mendukung -parameter untuk langsung keluaran ke stdout daripada file - coba saja.
Trauma Digital
1
@ DigitalTrauma itu bukan uuoc. Saya percaya kucing adalah yang tercepat yang bisa Anda dapatkan jika hanya mencetak, tetapi sebenarnya Anda dapat menggunakan perintah lain >(grep something)agar lebih bermanfaat. BTW, dukungan pdftotext 3.04 do saya -sebagai file output, jadi saya sedikit terkejut dengan seluruh diskusi.
jimmij
1
@terdon Saya benci menjadi ngotot, tapi ini sepertinya tidak berhasil. Secara khusus tidak ada bedanya dengan menjalankan pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf", yang menempatkan output dalam file yang dipanggil C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.txt, tetapi tidak ada teks yang di-output ke STDOUT untuk disalurkan ke program lain.
Trauma Digital
1
@DigitalTrauma itu tidak ngotot! Itu saya menjadi idiot. Terima kasih telah menunjukkannya dan tolong jangan pernah meminta maaf ketika menunjukkan kesalahan. Saya lebih suka kesalahan saya ditunjukkan kepada saya dan jadi belajar sesuatu daripada meninggalkannya di sana dalam semua kemuliaan yang meragukan.
terdon
-2
cmd tty

ttymengembalikan nama terminal yang terhubung stdout.

jas
sumber
Saya tidak yakin bagaimana ini menjawab pertanyaan, yaitu tentang menggabungkan perintah; mungkin Anda mengembangkan dengan contoh bagaimana Anda akan mencapai itu.
Dhag
Saya kira Anda mengatakan untuk memeriksa dengan ttynama terminal, dan kemudian menggunakan file itu sebagai keluaran, misalnya pdftotext file.pdf /dev/pts/2. Dalam hal itu, saya setuju.
jimmij
Itu dapat disingkat / diotomatisasi untuk ; yang umumnya akan setara dengan . Tetapi pendekatan ini mengasumsikan bahwa tujuannya adalah untuk menampilkan output (yaitu, di terminal), dan bukan itu pertanyaannya (lihat komentar pada jawaban terdon untuk beberapa klarifikasi tentang arti pertanyaan). prog1  input_file $(tty)prog1  input_file /dev/ttyprog1
Scott