Псевдофайли для тимчасових даних


98

Я часто хочу надсилати відносно короткі рядкові дані (хоча може бути декілька рядків) для програм командного рядка, які приймають лише введення з файлів (наприклад, wdiff) повторно. Звичайно, я можу створити один або кілька тимчасових файлів, зберегти туди рядок і запустити команду з ім'ям файла в якості параметра. Але мені здається, що ця процедура була б дуже неефективною, якщо дані насправді записуються на диск, а також вона може зашкодити диску більше, ніж потрібно, якщо я повторюю цю процедуру багато разів, наприклад, якщо я хочу подавати окремі рядки довгого тексту файли до wdiff. Чи є рекомендований спосіб обійти це, скажімо, використовуючи псевдофайли, такі як труби, для тимчасового зберігання даних, фактично не записуючи їх на диск (або записуючи їх, лише якщо вони перевищують критичну довжину). Зауважте, що wdiff бере два аргументи і,wdiff <"text".


Чи можна це вирішити через xargs?
NN

Не знаю, але мені було б очевидно, як. Наскільки я розумію xargs, вводяться рядки вводу з аргументів файлових рядків для команди. Але мені потрібно навпаки.
highsciguy

@rahmu У мене був погляд, але я думаю, що тут проблема дещо інша. Принаймні, я не бачу, як допоможуть відповіді. Прийнята відповідь про належне створення тимчасових файлів - це, по суті, те, чого я не хочу уникати, якщо ні, то існує якийсь тип буферизації, який фактично заважає писати файли. Я обмежено розумію, як працюють тимчасові файли!
highsciguy

Що не так echo $data_are_here | dumb_program?
vonbrand

1
Це підтримувало б лише один вхідний файл, і не всі програми читали б з stdin.
highsciguy

Відповіді:


55

Використовуйте названу трубу . Для ілюстрації:

mkfifo fifo
echo -e "hello world\nnext line\nline 3" > fifo

-eКаже відлуння , щоб правильно інтерпретувати втечу нового рядка ( \n). Це заблокує, тобто ваша оболонка буде висіти, поки щось не прочитає дані з труби.

Відкрийте іншу оболонку десь і в тому самому каталозі:

cat fifo

Ви прочитаєте луну, яка випустить іншу оболонку. Хоча труба існує як файловий вузол на диску, дані, що проходять через неї, не мають; все це відбувається в пам'яті. Ви можете фоном ( &) відлуння.

Труба має 64-буферний буфер (на Linux) і, як сокет, заблокує записувач, коли він заповнений, тому ви не втратите дані до тих пір, поки не передчасно вб'єте письменника.


Добре, спасибі, це працює також з двома названими трубами та wdiff. Але я подумав зрозуміти, що для труби в якості буфера є певний (невеликий) об'єм пам'яті. Що станеться, якщо я перевищую розмір буфера?
highsciguy

Я додав заключний абзац з цього питання.
goldilocks

3
/tmpв більшості дистрибутивів налаштовано на використання tmpfsфайлової системи, яка знаходиться в оперативній пам'яті. Коли ви пишете файл, /tmpвін переходить безпосередньо до вашої оперативної пам’яті, що робить це гарною відповіддю для напівстійких файлів, до яких потрібно швидко отримати доступ та переписати багато разів.

129

У Bash ви можете використовувати command1 <( command0 )синтаксис перенаправлення, який перенаправляє command0stdout і передає його значенню, command1яке приймає ім'я файлу як аргумент командного рядка. Це називається процес заміщення .

Деяким програмам, які беруть аргументи командного рядка назви, насправді потрібен реальний файл з випадковим доступом, тому ця методика не працюватиме для них. Однак він прекрасно працює з wdiff:

user@host:/path$ wdiff <( echo hello; echo hello1 ) <( echo hello; echo hello2 )
hello
[-hello1-]
{+hello2+}

На задньому плані це створює FIFO, <( )передає команду всередину до FIFO і передає дескриптор файлів FIFO як аргумент. Щоб побачити, що відбувається, спробуйте використати його echoдля друку аргументу, не роблячи з ним нічого:

user@host:/path$ echo <( echo hello )
/dev/fd/63

Створення названої труби є більш гнучким (якщо ви хочете написати складну логіку перенаправлення за допомогою декількох процесів), але для багатьох цілей цього достатньо, і, очевидно, простіше у використанні.

Існує також >( )синтаксис, коли ви хочете використовувати його як вихід, наприклад

$ someprogram --logfile >( gzip > out.log.gz )

Дивіться також шпаргалку Bash redirections для відповідних методик.


Це не підтримується в KSH
chanchal1987

5
ksh придумав це. Ви використовуєте варіант ksh, який не підтримує його
Ніл Макгуйган,

2
Деяким програмам, які беруть аргументи командного рядка назви, насправді потрібен реальний файл з випадковим доступом, тому ця методика не працюватиме для них. Що ти робиш у цих випадках. Наприклад, ssh -F <(vagrant ssh-config) defaultбуло б дуже приємно, але на жаль.
Сукіма

10

wdiff - це особливий випадок, оскільки він вимагає 2 аргументів імені файлів, але для всіх команд, які вимагають лише 1 аргумент, і які вперто відмовляються приймати що-небудь, крім аргументу імені файлу, є 2 варіанти:

  • Ім'я файлу '-' (тобто знак мінус) працює приблизно в 1/2 часу. Здається, це залежить від команди, про яку йдеться, і від того, чи розробник команди вловлює цей випадок і обробляє його так, як очікувалося. напр

    $> ls | кішка -

  • Існує файл psuedo з іменем / dev / stdin, який існує в Linux і може бути використаний, якщо ім'я файлу абсолютно необхідне командою. Це, швидше за все, спрацює, оскільки не вимагає жодної спеціальної обробки імен файлів від команди. Якщо фіфо працює, або метод заміни баш- процесу працює, то це також має працювати і не має особливих оболонок. напр

    $> ls | кіт / дев / стдін


1
менше і openssl, як / dev / stdin, а не / dev / fd / NUM :-)
вугор ghEEz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.