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

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

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

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

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

#!/bin/bash
if [ $# -ne 2 ]; then exit 1; fi
f=$(mktemp)
() > $f
if [ $? -eq 0 ]; then ( $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); Не стесняйтесь публиковать лучший.

8
задан Mateusz Kowalczyk
20.11.2022 20:17 Количество просмотров материала 3040
Распечатать страницу

3 ответа

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

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 и предоставить его в качестве входных данных для другой программы в качестве параметра путь:

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

первый rm -f "$f" необходимо потому что mktemp не только генерирует имя файла; он создает файл.  Если мы не удаляйте его,mkfifo не удастся.  (В качестве альтернативы мы могли бы использовать mktemp -u, который генерирует имя файла без создания файла.)

___________

1 является ли Unix "изобрел" трубы несколько спорным.  По словам эволюция системы разделения времени Unix (Деннис М. Ритчи) (PDF), концепция существовала в других формах в других местах до появления труб в Unix в 1972 году.

2 или, в общий, любой поток выхода; например,cp somefile "$f" или dd … of="$f"

4
отвечен Scott 2022-11-22 04:05

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

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

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

5
отвечен Aluísio A. S. G. 2022-11-22 06:22

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

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

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

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

#!/bin/bash
[[ $# -gt 0 ]] && exec 0< <(cat "$@")
n=0
while read line; do
    echo "$((++n)) $line"
done
-1
отвечен glenn jackman 2022-11-22 08:39

Постоянная ссылка на данную страницу: [ Скопировать ссылку | Сгенерировать QR-код ]

Ваш ответ

Опубликуйте как Гость или авторизуйтесь

Имя
Вверх