Псевдофайлы для временных данных

98

Я часто хочу передавать относительно короткие строковые данные (хотя это может быть несколько строк) в программы командной строки, которые принимают входные данные только из файлов (например, wdiff) повторяющимся образом. Конечно, я могу создать один или несколько временных файлов, сохранить там строку и запустить команду с именем файла в качестве параметра. Но мне кажется, что эта процедура будет крайне неэффективной, если на самом деле данные будут записаны на диск, а также может нанести вред диску больше, чем необходимо, если я повторю эту процедуру много раз, например, если я хочу передать отдельные строки длинного текста файлы в wdiff. Есть ли рекомендуемый способ обойти это, скажем, с помощью псевдофайлов, таких как каналы, для временного хранения данных без фактической записи их на диск (или записи, только если они превышают критическую длину). Обратите внимание, что wdiff принимает два аргумента и,wdiff <"text",

highsciguy
источник
Это можно решить с помощью xargs?
NN
Не знаю, но это не было бы очевидно для меня, как. Насколько я понимаю, xargsбудет делать входные строки из файловых аргументов строки для команды. Но мне нужно наоборот.
Highsciguy
@rahmu Я посмотрел, но я думаю, что проблема там немного другая. По крайней мере, я не понимаю, как ответы помогут. Принятый ответ для правильного создания временных файлов - это, по сути, то, чего я не хочу избегать, если нет какой-то буферизации, которая фактически мешает записи файлов. У меня ограниченное понимание того, как работают временные файлы!
Highsciguy
Что не так с echo $data_are_here | dumb_program?
vonbrand
1
Это будет поддерживать только один входной файл, и не все программы будут читать из стандартного ввода.
Highsciguy

Ответы:

55

Используйте именованную трубу . В качестве иллюстрации:

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

-eГоворит эхо , чтобы правильно интерпретировать побег новой строки ( \n). Это будет блокировать, т. Е. Ваша оболочка будет зависать, пока что-то не прочитает данные из канала.

Откройте другую оболочку где-нибудь и в том же каталоге:

cat fifo

Вы прочтете эхо, которое освободит другую оболочку. Хотя канал существует в виде файлового узла на диске, данных, проходящих через него, нет; все это происходит в памяти. Вы можете фон ( &) эхо.

Канал имеет буфер 64 КБ (в linux) и, подобно сокету, блокирует запись при заполнении, поэтому вы не потеряете данные, если не преждевременно уничтожите программу записи.

лютик золотистый
источник
Хорошо, спасибо, это работает также с двумя именованными каналами и wdiff. Но я подумал, что понимаю, что для канала в качестве буфера имеется определенный (небольшой) объем памяти. Что произойдет, если я превышу размер буфера?
Highsciguy
Я добавил последний абзац по этому вопросу.
Златовласка
3
/tmpв большинстве дистрибутивов используется для настройки tmpfsфайловой системы, находящейся в оперативной памяти. Когда вы записываете файл в /tmpнего, он напрямую попадает в вашу оперативную память, что является хорошим ответом для полуэластичных файлов, к которым нужно быстро обращаться и много раз переписывать.
131

В 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 для связанных методов.

Механическая улитка
источник
Это не поддерживается в KSH
chanchal1987
5
Кш изобрел это. Вы используете вариант ksh, который не поддерживает его
Нил Макгиган
2
Некоторым программам, которые принимают аргументы командной строки имени файла, на самом деле нужен настоящий файл с произвольным доступом, поэтому этот метод для них не подойдет. Что вы делаете в этих случаях. Например ssh -F <(vagrant ssh-config) defaultбыло бы очень приятно, но увы.
Sukima
10

wdiff представляет собой особый случай из-за этого требует 2 аргумента имени файла, но и для всех команд, которые требуют только 1 аргумента и который упорно отказываются принять что-либо, кроме имени файла аргумента, есть 2 варианта:

  • Имя файла '-' (то есть знак минус) работает примерно в половине случаев. Кажется, это зависит от рассматриваемой команды и от того, разработчик команды перехватывает этот случай и обрабатывает его, как ожидалось. например

    $> ls | кошка -

  • Существует файл psuedo с именем / dev / stdin, который существует в linux и может использоваться, если имя файла абсолютно необходимо для команды. Это с большей вероятностью сработает, поскольку не требует какой-либо специальной обработки имени файла из команды. Если fifo работает или работает метод подстановки процесса bash, то это также должно работать и не зависит от оболочки. например

    $> ls | cat / dev / stdin

dabuntu
источник
1
меньше и openssl, как / dev / stdin, а не / dev / fd / NUM :-)
угорь ghEEz