Прозрачное использование временных файлов в качестве средства трубопровода [закрыто]

3

Как наверняка знают многие из нас, всегда полезно, чтобы ваша программа принимала ввод stdin. Очень многие программы допускают такую ​​среду * nix. Это позволяет нам делать классные вещи, такие как трубопровод echo "foo" | less, Довольно часто можно обнаружить, что cat barfile | baz логически эквивалентно baz barfile как за кулисами это просто чтение строк в любом случае.

В настоящее время существует намного больше программ, по которым невозможно передать по умолчанию. У некоторых программ есть флаг, который все еще учитывает поведение, упомянутое выше, но многие не делают.

Теперь мой вопрос: существует ли временный файловый канал?

Теперь, с моей буквально несуществующей способностью писать Bash и около 5 минут в Google, я придумал это

#!/bin/bash
if [ $# -ne 2 ]; then exit 1; fi
f=$(mktemp)
($1) > $f
if [ $? -eq 0 ]; then ($2 $f); else exit $?; fi
rm $f

Называя этот fpipe, мы можем сделать такие вещи, как fpipe 'wget -O- www.example.com' baz где baz - это программа, в которую мы не можем перейти, но можем baz file,

Мой вопрос, как мы можем сделать лучше. Я подозреваю, что, обладая большим знанием Bash, переписать приведенный выше скрипт, чтобы принять любое количество аргументов, было бы довольно тривиально (так что мы можем делать такие вещи, как fpipe 'foo x' bar baz где с помощью трубопровода мы могли бы сделать что-то вроде foo x | bar | baz, Бах, мы могли бы, вероятно, смешать два и в конечном итоге с такими вещами fpipe 'wget -O- www.example.org | rev' baz,

Существует ли существующая конструкция, которая достигает этого? Я полагаю, я видел конструкцию своего рода foo x > bar < baz или что-то в этом роде. Я бы подумал, что это довольно распространенная проблема, но мои поиски ничего не поднимают. Это означает, что я либо недостаточно усердно ищу, либо упускаю что-то довольно очевидное.

Если для достижения этого не существует надлежащего пути (TM), возможно ли определить удобный синтаксис? Сказать, foo x |> baz | rev где |> в значительной степени прямо переводится на мой сценарий.

PS: я знаю, что мой / script / очень хрупкий и наивный (например, выход из не-0); не стесняйтесь размещать лучшие.

Mateusz Kowalczyk
источник
Вы ищете решения, специально предназначенные для bash или zsh? Между этими двумя вы получите удвоенные результаты. Даже при наличии только одного интерпретатора оболочки вы, вероятно, получите несколько различных методов или тактик. Этот вопрос, кажется, плохо соответствует среде, в которой вы его задали.
killermist

Ответы:

4

Это будет работать (в принципе) в любой оболочке, но для этого требуется «достаточно свежая версия» операционной системы:

wget -O- www.example.com | baz /dev/stdin

когда /dev/stdin существует, как правило, это символическая ссылка на /proc/self/fd/0так что если ваша коробка не имеет /dev/stdin, проверить /proc/self/fd/0,


Конечно изобретение труб был одним из великих нововведений Unix. 1 Временные промежуточные файлы в порядке, но может иметь затраты на производительность, и в случае

 program_that_produces_gobs_of_output  | Grep  regular_expression_that_matches_very_few_lines 

у вас может возникнуть проблема с невозможностью размещения файла (весь вывод из первой команды) на диске. Итак, лучшее из обоих миров - использовать именованную трубу. Это позволяет вам захватить стандартный вывод из некоторой программы 2 и предоставить его в качестве входных данных для другой программы в качестве параметра pathname:

f=$(mktemp)  &&  rm -f "$f"  &&  mkfifo "$f"
$1 >> "$f" &
$2 "$f"
rm -f "$f"

Первый rm -f "$f" является необходимым так как mktemp не только генерирует имя файла; он создает файл. Если мы не удалим его, mkfifo не удастся. (В качестве альтернативы мы могли бы использовать mktemp -u, который генерирует имя файла без создания файла.)
___________
1 Если Unix «изобрели» трубы несколько спорно. В соответствии с Эволюция системы разделения времени Unix (От Dennis M. Ritchie) (PDF), концепция существовала в других формах в других местах до появления труб в Unix в 1972 году.

2 или вообще любой поток вывода; например, из cp некий-файл «$ Е» или же dd … of="$f"

Scott
источник
5

С достаточно недавней версией Bash:

$ baz <(wget -O- www.example.com)

Это называется процесс замены ,

Aluísio A. S. G.
источник
+1 Замена процесса доступна по крайней мере с версии 2.0, выпущенной в 1997 году.
chepner
@chepner Вау. Я думаю, что мне нужно найти страницу «Что нового в bash 4.0».
Aluísio A. S. G.
-1

Вот два метода, чтобы ваш скрипт действовал одинаково, если заданы аргументы файла или если он должен читать строки из stdin:

1) cat файлы, используйте специальное имя файла "-", если в командной строке не указаны файлы

#!/bin/bash
[[ $# -eq 0 ]] && set -- "-"
n=0
while read line; do
    echo "$((++n)) $line"
done < <(cat "$@")

2) если файлы указаны, поместите их содержимое в поток stdin скрипта

#!/bin/bash
[[ $# -gt 0 ]] && exec 0< <(cat "$@")
n=0
while read line; do
    echo "$((++n)) $line"
done
glenn jackman
источник