Як стандартний вхід однієї програми може бути переданий як аргумент іншій?


17

Скажімо, існує програма, яка бере два аргументи; вхідний файл і вихідний файл.

Що робити, якщо я не хочу зберігати цей вихідний файл на диску, а краще передати його безпосередньо stdinіншій програмі. Чи є спосіб досягти цього?

Дуже багато команд, які я зустрічаю в Linux, дають можливість передавати "-" як аргумент вихідного файлу, який робить те, що я вказав вище. Це тому, що передача stdinпрограми як аргументу неможлива? Якщо це так, як це робити?

Приклад, як я зображував би це:

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

Оболонка, яку я використовую, - це баш.


1
cat <file | cmd /dev/fd/0працює на більшості уніцій.
mikeserv

Не працює для мене. Пробували з: cat < README.txt | cp /dev/fd/0. Там сказаноcp: missing destination file operand after ‘/dev/fd/0’ Try 'cp --help' for more information.
Dziugas

1
program input-file /dev/stdout | another-program? Також зауважте, що echoнічого не читається зі stdin.
yaegashi

1
@Dziugas - звичайно, ні - ви не можете cpрозмістити файл ніде. echo 1 2 3| cp /dev/fd/0 /dev/ttyнадрукує 1 2 3. І, до речі, /dev/fd/[num]швидше спрацює, ніж /dev/std(in|out|err)у більшості випадків. Дивіться портативність файлових посилань-дескрипторів про те, що ви можете очікувати роботи.
mikeserv

1
Хороша програма UNIX записує до стандартного виводу, залишаючи його користувачеві вирішувати, чи бажають вони переадресувати на файл або на іншу команду.
Хорхе Букарань

Відповіді:


13

Якщо програма підтримує запис у будь-який дескриптор файлу, навіть якщо він не може шукати, ви можете використовувати /dev/stdoutяк вихідний файл. Це символьне посилання /proc/self/fd/1на мою систему. Дескриптор файлу 1 - stdout.


Це вирішило мій запит. Тож чи немає способу це зробити, коли програмі потрібно шукати?
Дзюгас

3
Якщо ви намагаєтеся не допустити доступу до диска, ви можете записати файл у / dev / shm /, однак, якщо ви не хочете жодного файлу у файловій системі, то, наскільки я знаю, немає можливості шукати далі труба. Шукати вперед означає, що доведеться зберігати все в пам'яті, поки не досяг цієї точки вперед, а пошук назад означає, що буферизував усе в пам'яті.
TiCPU

pdftotextяк і багато (але не всі) інші утиліти, які також підтримують -цю програму (яка працюватиме навіть у системах, які не підтримують / dev / stdout, або де / dev / stdout не працюють так, як очікувалося, як у Linux, де stdout не є труба). pdftotext file.pdf - | wc -c
Стефан Шазелас

11

На pdftotextчоловіковій сторінці:

Якщо текстовий файл є ´-, текст надсилається до stdout.

Тож у цьому випадку все, що вам потрібно, це:

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

Або якщо ви хочете передати це на STDIN іншої програми:

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

Використання -як замінника імені файлів є умовою, яку виконують багато утиліти (включаючи pdftotext), коли ми хочемо ввести дані STDIN або вивести в STDOUT. Однак не всі комунальні підприємства дотримуються цієї конвенції. У цьому випадку ідіоматичним способом зробити це в bash є використання підстановки процесу :

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

Тут >( )поводиться багато в чому, як переданий файл my_utility, але замість того, щоб бути реальним файлом, потік передається в stdin вмісту, що міститься, тобто cat. Отже, текст у кінцевому рахунку повинен виводитись так, як потрібно.

Використання catмайже завжди викликає дзвінки тривоги UUOC на таких форумах. Я стверджую, що якщо утиліта не підтримує -, це корисне використання cat, хоча якщо є якісь способи зробити цю заміну безcat , то я все вуха ;-).

Однак, якщо (як зазначено в питанні) кінцевим пунктом призначення потоку є STDIN іншої програми, то цю catмітку можна усунути:

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

2
І дозволю мені ще раз: якщо prog2записує в stdout, це краще ніж , тому що форма чекає завершення (тобто до того, як оболонка видасть наступне підказку або перейде до наступної команди (наприклад, після або )), тоді як -без форма очікує лише на заповнення. Також після форми є статус виходу з , тоді як, в іншому, це статус виходу з . (Ви платите свої гроші, і ви приймаєте свій вибір.)prog1 input_file >( cat ) | prog2prog1 input_file >( prog2 )catprog2;&&catprog1cat$?prog2$?prog1
Скотт

4

Якщо ваша оболонка їх підтримує, найпростішим способом здійснення таких маніпуляцій буде використання підстановки процесу : <(…)і >(…). Це працює в bash, zsh і ksh та, можливо, в інших оболонках. Наприклад:

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

Однак це не допоможе в прикладі, який ви констатуєте, оскільки pdftotextбуде збережено у текстовому файлі. Хоча найкращим вибором (крім очевидного використання -) є використання, /dev/stdoutяк запропонував @TiCPU, ви також можете використовувати іншу функцію оболонки. Конструкція !:Nпосилається на N-й аргумент попередньої команди. Тому ви можете зробити:

$ pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf"  out.txt
$ cat !:2

1
Хоча я погоджуюся, що cat <()може бути корисним у деяких ситуаціях, проте в цьому сценарії він взагалі не працює. Проблема (дуже погано описана ОП, я повинен визнати) полягає в тому, що вона pdftotextбере два аргументи: вхідний файл і вихідний файл . Якщо другий аргумент відсутній, то він нічого не виробляє, а cat <(pdftotext "file.pdf")також нічого не повертає. pdftotextКоманду можна обдурити , подавши >(cat)як другий аргумент, як відповів Digital Trauma, але cat <()тут безглуздо. Очевидно, у pdftotextвипадку, коли найкраще просто використовувати -в якості імені вихідного файлу.
jimmij

1
@Scott Як моя відповідь є UUOC? Як би ви зробили цей процес заміщення без кота? >( )ефективно передаватиме потік до будь-якого процесу, який знаходиться всередині, тому нам фактично потрібен catтут для виведення цього потоку. Зазвичай ми повинні бути в змозі зробити щось на кшталт pdftotext input.pdf -, але, мабуть pdftotext, не підтримує -параметр для виведення безпосередньо на stdout замість файлу - спробуйте.
Цифрова травма

1
@DigitalTrauma це не uuoc. Я вважаю, що кіт - це найшвидший ви можете отримати у випадку просто друку, але насправді ви можете скористатися іншою командою як >(grep something)кориснішою. До речі, моя pdftotext 3.04 робити підтримка в -якості вихідного файлу, так що я трохи здивований всієї дискусії.
jimmij

1
@terdon Я ненавиджу бути стикером, але це, здається, не працює. Зокрема, він не відрізняється від запущеного pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf", який ставить вихід у файл, який називається C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.txt, але жоден текст не виводиться в STDOUT для передачі в іншу програму.
Цифрова травма

1
@DigitalTrauma це не є стикером! Це я ідіот. Дякуємо, що вказали на це і будь ласка, ніколи не вибачайтесь, коли вказували на помилки. Я б швидше хотів би, щоб моя помилка вказувала на мене, і тому чогось навчитися, ніж залишити його там у всій сумнівній красі.
тердон

-2
cmd tty

ttyповертає назву підключеного до нього терміналу stdout.


Я не впевнений, як це відповідає на питання, що стосується комбінування команд; можливо, ви розширюєте прикладом того, як ви цього домоглися.
даг

Я думаю, ви говорите, щоб перевірити ttyназву терміналу, а потім використовувати цей файл, наприклад, як вихід pdftotext file.pdf /dev/pts/2. У такому випадку я згоден.
jimmij

Це можна скоротити / автоматизувати ; що, як правило, буде рівнозначним . Але цей підхід передбачає, що мета полягає у відображенні результату (тобто в терміналі), і це не те, про що задається питання (див . Коментарі до відповіді тердона для деякого роз'яснення сенсу питання). prog1  input_file $(tty)prog1  input_file /dev/ttyprog1
Скотт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.