Jak standardowe wejście jednego programu może być przekazywane jako argument do drugiego?

17

Powiedzmy, że istnieje program, który przyjmuje dwa argumenty; plik wejściowy i plik wyjściowy.

Co jeśli nie chcę zapisać tego pliku wyjściowego na dysk, a raczej przekazać go bezpośrednio stdininnemu programowi. Czy istnieje sposób na osiągnięcie tego?

Wiele poleceń, na które natrafiłem w systemie Linux, udostępnia opcję przekazania „-” jako argumentu pliku wyjściowego, który robi to, co określiłem powyżej. Czy to dlatego, że przekazanie stdinprogramu jako argumentu nie jest możliwe? Jeśli tak, to jak to robimy?

Przykładem tego, w jaki sposób obrazowałbym za pomocą tego jest:

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

Powłoka, której używam, to bash.

Dziugas
źródło
1
cat <file | cmd /dev/fd/0działa na większości jednorożców.
mikeserv
Nie działa dla mnie. Próbowaliśmy go z: cat < README.txt | cp /dev/fd/0. Powiedziałcp: missing destination file operand after ‘/dev/fd/0’ Try 'cp --help' for more information.
Dziugas,
1
program input-file /dev/stdout | another-program? Zauważ też, że echonic nie czyta ze standardowego wejścia.
yaegashi,
1
@Dziugas - oczywiście nie - cpnigdzie nie można utworzyć pliku. echo 1 2 3| cp /dev/fd/0 /dev/ttywydrukuje 1 2 3. Nawiasem mówiąc, /dev/fd/[num]jest bardziej prawdopodobne, że zadziała niż /dev/std(in|out|err)w większości przypadków. Zobacz Przenośność linków deskryptorów plików, aby dowiedzieć się, gdzie możesz pracować.
mikeserv
1
Dobry program UNIX zapisuje na standardowe wyjście, pozostawiając użytkownikowi decyzję, czy chce przekierować do pliku, czy potoku do innego polecenia.
Jorge Bucaran,

Odpowiedzi:

13

Jeśli program obsługuje zapis do dowolnego deskryptora pliku, nawet jeśli nie może wyszukiwać, możesz użyć go /dev/stdoutjako pliku wyjściowego. To jest dowiązanie symboliczne do /proc/self/fd/1mojego systemu. Deskryptor pliku 1 jest stdout.

TiCPU
źródło
To rozwiązało moje zapytanie. Więc czy nie ma sposobu, aby to zrobić, gdy program musi szukać?
Dziugas,
3
Jeśli próbujesz uniemożliwić dostęp do dysku, możesz zapisać plik w / dev / shm /, jednak jeśli nie chcesz żadnego pliku w systemie plików, o ile wiem, nie ma sposobu, aby szukać na rura. Wyszukiwanie do przodu oznacza, że ​​musiałoby buforować wszystko w pamięci, dopóki nie osiągnie tego punktu do przodu, a wyszukiwanie do tyłu oznacza buforowanie wszystkiego w pamięci.
TiCPU,
pdftotextpodobnie jak wiele (ale nie wszystkie) innych narzędzi obsługujących -to (które działałyby nawet na systemach, które nie obsługują / dev / stdout, lub gdzie / dev / stdout nie działają zgodnie z oczekiwaniami, tak jak w Linuksie, gdzie stdout nie jest rura). pdftotext file.pdf - | wc -c
Stéphane Chazelas,
11

Ze strony podręcznika pdftotext:

Jeśli plik tekstowy to ´-, tekst jest wysyłany na standardowe wyjście.

Więc w tym przypadku wszystko czego potrzebujesz to:

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

Lub jeśli chcesz potokować to do STDIN innego programu:

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

Używanie -jako zamiennika nazwy pliku jest konwencją stosowaną przez wiele narzędzi (w tym pdftotext), gdy chcemy wprowadzić dane wejściowe ze STDIN lub dane wyjściowe do STDOUT. Jednak nie wszystkie narzędzia są zgodne z tą konwencją. W takim przypadku idiomatycznym sposobem na zrobienie tego w bash jest użycie podstawienia procesu :

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

Tutaj >( )zachowuje się w dużej mierze jak plik przesłany do my_utility, ale zamiast być prawdziwym plikiem, strumień jest przesyłany strumieniowo do wejścia standardowego zawartego procesu, tj. Cat. Tak więc tekst powinien ostatecznie zostać wydrukowany zgodnie z wymaganiami.

Użycie catprawie zawsze uruchamia dzwonki alarmowe UUOC na takich forach. Twierdzę, że jeśli narzędzie nie obsługuje -, to jest to użyteczne zastosowanie cat, chociaż jeśli istnieją sposoby na zastąpienie tego procesu bez cat, to jestem cały w uszach ;-).

Jeśli jednak (jak stwierdza pytanie) ostatecznym miejscem docelowym strumienia jest STDIN innego programu, wówczas catmożna go wyeliminować:

my_utility "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" >( another_prog )
Cyfrowa trauma
źródło
2
I pozwólcie, że cofnę się jeszcze raz: jeśli prog2pisze na standardowe wyjście, jest lepsze niż , ponieważ formularz czeka na zakończenie (tj. Zanim powłoka wyda następny monit lub przejdzie do następnego polecenia (np. Po lub )), podczas gdy - bez formularza czeka tylko na wypełnienie. Również po formularzu jest status wyjścia z , podczas gdy w drugim jest status wyjścia z . (Płacisz pieniądze i sam wybierasz.)prog1 input_file >( cat ) | prog2prog1 input_file >( prog2 )catprog2;&&catprog1cat$?prog2$?prog1
Scott,
4

Jeśli twoja powłoka je obsługuje, najprostszym sposobem wykonywania takich manipulacji byłoby użycie podstawiania procesów : <(…)i >(…). Działa to w bash, zsh i ksh i ewentualnie w innych powłokach. Na przykład:

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

Jednak to nie pomoże w podanym przykładzie, ponieważ pdftotextzostanie zapisany w pliku tekstowym. Podczas gdy twój najlepszy wybór (oprócz oczywistego wyboru- ) jest użycie /dev/stdoutzgodnie z sugestią @TiCPU, możesz również użyć innej funkcji powłoki. Konstrukt !:Nodwołuje się do N-tego argumentu poprzedniego polecenia. Dlatego możesz:

$ pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf"  out.txt
$ cat !:2
terdon
źródło
1
Chociaż zgadzam się, że cat <()może to być przydatne w niektórych sytuacjach, w tym scenariuszu jednak w ogóle nie działa. Problem (bardzo źle opisany przez OP, muszę przyznać) polega na tym, że pdftotextwymaga dwóch argumentów: pliku wejściowego i pliku wyjściowego . Jeśli brakuje drugiego argumentu, to nic nie produkuje, więc cat <(pdftotext "file.pdf")również nic nie zwraca. Można oszukiwać pdftotextpolecenia, podając >(cat)jako drugi argument, na który odpowiedział Digital Trauma, ale cat <()tutaj nie ma sensu. Oczywiście w pdftotextprzypadku, gdy najlepiej jest użyć -jako nazwy pliku wyjściowego.
jimmij
1
@Scott Jaka jest moja odpowiedź UUOC? Jak zrobiłbyś ten proces zastępowania bez kota? >( )skutecznie potokuje strumień do dowolnego procesu, który jest w środku - tak naprawdę potrzebujemy cattutaj, aby wyprowadzić ten strumień. Zwykle powinniśmy być w stanie zrobić coś podobnego pdftotext input.pdf -, ale najwyraźniej pdftotextnie obsługuje -parametru do wyświetlania bezpośrednio na wyjściu zamiast do pliku - spróbuj.
Cyfrowa trauma
1
@DigitalTrauma to nie jest uuoc. Wierzę, że cat jest najszybszy, jaki możesz uzyskać w przypadku samego drukowania, ale w rzeczywistości możesz użyć innego polecenia, >(grep something)aby być bardziej użytecznym. BTW, moja pdftotext 3.04 Do wsparcia -w postaci pliku wyjściowego, więc jestem trochę zaskoczony całej dyskusji.
jimmij
1
@terdon Nienawidzę być trikowcem, ale wydaje się, że to nie działa. W szczególności nie różni się to od działania pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf", które umieszcza dane wyjściowe w pliku o nazwie C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.txt, ale żaden tekst nie jest wysyłany do STDOUT w celu przesłania do innego programu.
Cyfrowa trauma
1
@DigitalTrauma, który nie jest stickler! To jestem idiota. Dziękujemy za wskazanie tego i nigdy nie przepraszaj za wskazanie błędów. Wolałbym, żeby mój błąd został mi wskazany, więc naucz się czegoś, niż pozostaw go w pełnej wątpliwej chwale.
terdon
-2
cmd tty

ttyzwraca nazwę podłączonego terminala stdout.

jas
źródło
Nie jestem pewien, jak to odpowiada na pytanie, które dotyczy łączenia poleceń; być może rozszerzysz się o przykład, w jaki sposób to osiągniesz.
dhag
Wydaje mi się, że mówisz o sprawdzeniu ttynazwy terminala, a następnie na przykład użyj tego pliku jako danych wyjściowych pdftotext file.pdf /dev/pts/2. W takim przypadku zgadzam się.
jimmij
Można to skrócić / zautomatyzować do ; co na ogół będzie równoważne z . Ale takie podejście zakłada, że celem jest wyświetlanie wyjścia (czyli w terminalu), a nie to pytanie jest pytaniem (patrz komentarze na temat odpowiedzi terdon za jakiegoś wyjaśnienia w rozumieniu pytanie). prog1  input_file $(tty)prog1  input_file /dev/ttyprog1
Scott