Как использовать namedpipe в качестве временного файла?

Как использовать namedpipe в качестве временного файла?

Один из плагинов vim, который я использую, использует этот скрипт для передачи некоторых входных данных линтерам, которые не поддерживают чтение из stdin.

set -eu

# All of the following arguments are read as command to run.
file_extension="$1"
shift

temp_dir=$(mktemp -d 2>/dev/null || mktemp -d -t 'ale_linter')
temp_file="$temp_dir/file$file_extension"
trap 'rm -r "$temp_dir"' EXIT

while read -r; do
  echo "$REPLY" >> "$temp_file"
done

"$@" "$temp_file"

Сначала я был немного озадачен, почему они просто не использовали что-то подобное.

some input | some_program /dev/stdin

Но после того, как я попробовал ghcего в качестве линтера, я обнаружил, что он жалуется на /dev/stdin, говоря что-то о том, что это не настоящий файл (что на самом деле не так)

Так что мне интересно, могу ли я использовать namedpipe вместо временного файла. Причина, по которой я не совсем удовлетворен записью во временные файлы, заключается в состоянии SSD, и если есть лучший способ сделать это, почему бы не сделать это, верно?

решение1

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

Безымянные pipe(например, с |и /dev/stdin) или именованные не имеют значения ни в одном из этих случаев.

На самом деле, в Linux, /dev/stdinкогда stdin — это канал (с именем или без) и ведет себя точно так же, как именованный канал, программа не сможет отличить его /dev/stdinот настоящего именованного канала.

В других системах это не совсем то же самое, но по сути открытие /dev/stdinименованного канала даст вам файловый дескриптор канала, который невозможно найти ни тем, ни другим способом.

Итак, вам нужно создать временный файл. Обратите внимание, что некоторые оболочки делают это проще. С zsh, это просто:

#! /bin/zsh -
"$@" =(cat)

В Linux и оболочках с использованием удаленных временных файлов для документов here (например bash, zshи некоторых реализаций ksh), вы можете сделать следующее:

#! /bin/bash -
"$@" /dev/fd/3 3<< EOF
$(cat)
EOF

Однако это может исказить содержимое файла, если он содержит символы NUL или заканчивается пустыми строками.

Обратите внимание, что начиная с версии 5, bash делает временный файл here doc доступным только для чтения, поэтому, если приложению необходимо внести изменения в этот файл, вам нужно будет восстановить права на запись с помощью:

#! /bin/bash -
{
  chmod u+w /dev/fd/3 && # only needed in bash 5+
    "$@" /dev/fd/3
} 3<< EOF
$(cat)
EOF

Заметка об этом while readцикле, раз уж вы спросили.

First read -rбез имени переменной не является допустимым shсинтаксисом. shСинтаксис указан POSIX (ISO 9945, также IEEE Std 1003.1), как и Cсинтаксис указан ISO 9899.

Вэта спецификация, вы заметите, что readтребуется аргумент имени переменной. Поведение, когда вы его опускаете, следующее:неопределенныеи на практике различаются в зависимости от shреализации интерпретатора.

bashявляется интерпретатором GNU sh, как gccи компилятор GNU C. Оба bashимеют gccрасширения по сравнению с тем, что указано в этих стандартах.

В случае read, bashобрабатывается read -rтак, как если бы это было IFS= read -r REPLY. В спецификации POSIX IFS= read -r REPLYчитает stdin до тех пор, пока не \nбудет достигнут символ или конец ввода, и сохраняет считанные символы в $REPLYпеременной и возвращается суспехстатус выхода, если был прочитан символ новой строки (полная строка) илиотказв противном случае (например, EOF перед символом новой строки) и оставляет поведение неопределенным, если считанные данные содержат символы NUL или последовательности байтов, которые не образуют допустимые символы.

В случае bashон сохранит считанные байты, даже если они не образуют допустимые символы, и удалит символы NUL.

read -rпохож read -r REPLYна kshили zshи сообщает об ошибке в POSIX-подобных оболочках на основе yashили .ash

Поведение echoне определено, если только его аргументы не содержат символы обратной косой черты и первый из них не является -n.

Итак, подводя итог, если вы не знаете конкретную shреализацию (и версию), с которой имеете дело, вы не сможете сказать, что

while read -r; do
  echo "$REPLY" >> "$temp_file"
done

подойдет. В bashконкретном случае он сохранит stdin в temp_file только до тех пор, пока данные не содержат символы NUL, не заканчиваются символом новой строки и ни одна из строк не соответствует ^-[neE]+$расширенному регулярному выражению (и/или в зависимости от среды или того, как bashбыла скомпилирована, например, shOS/X, не содержит символы обратной косой черты).

Это такжеочень неэффективно и не так, как вы обрабатываете текст в оболочках.

Здесь вам нужно:

cat > "$temp_file"

catэтостандартная команда, который при отсутствии аргументов просто выводит свой stdin на stdoutкак есть.

Связанный контент