Wie verwende ich Namedpipe als temporäre Datei?

Wie verwende ich Namedpipe als temporäre Datei?

Ein von mir verwendetes Vim-Plugin nutzt dieses Skript, um einige Eingaben an Linter zu übergeben, die das Lesen von stdin nicht unterstützen.

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"

Zuerst war ich etwas verwirrt, warum sie nicht einfach so etwas verwendet haben

some input | some_program /dev/stdin

Aber nachdem ich es ghcals Linter versucht habe, habe ich festgestellt, dass es sich über /dev/stdin beschwert und sagt, dass es keine echte Datei ist (was es nicht ist).

Ich frage mich also, ob ich Namedpipe anstelle einer temporären Datei verwenden kann. Der Grund, warum ich mit dem Schreiben in temporäre Dateien nicht ganz zufrieden bin, ist der Zustand der SSD, und wenn es eine bessere Möglichkeit gibt, warum sollte ich sie nicht nutzen, oder?

Antwort1

Nein, die Programme, die diese Dateien ablehnen, lehnen sie normalerweise mit der Begründung ab, dass die Datei nichtsuchbar(Sie müssen an beliebigen Stellen oder nach dem Zurückspulen usw. mehrmals auf den Inhalt zugreifen.) Oder sie möchten die Datei mehrmals öffnen. Sie möchten möglicherweise auch (einen Teil) der Datei neu schreiben oder abschneiden.

Ob unbenannte pipe(wie mit |und /dev/stdin) oder benannte, macht in all diesen Fällen keinen Unterschied.

Tatsächlich verhält sich unter Linux /dev/stdindie Standardeingabepipe (mit oder ohne Namen) genau wie eine benannte Pipe, d. h. das Programm könnte sie nicht /dev/stdinvon einer echten benannten Pipe unterscheiden.

Auf anderen Systemen ist es nicht genau dasselbe, aber tatsächlich /dev/stdinerhalten Sie durch das Öffnen einer benannten Pipe einen Dateideskriptor für eine Pipe, der auf keine Weise gesucht werden kann.

Sie müssen also die temporäre Datei erstellen. Beachten Sie, dass einige Shells dies einfacher machen. Mit zshist es einfach:

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

Unter Linux und mit Shells, die gelöschte temporäre Dateien für Here-Dokumente verwenden (wie bashund zsheinige Implementierungen von ksh), können Sie Folgendes tun:

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

Dies kann jedoch zu fehlerhaften Inhalten der Datei führen, wenn diese NUL-Zeichen enthält oder mit leeren Zeilen endet.

Beachten Sie, dass Bash seit Version 5 die temporäre Datei „Here doc“ schreibgeschützt macht. Wenn die Anwendung also Änderungen an dieser Datei vornehmen muss, müssen Sie die Schreibberechtigungen wie folgt wiederherstellen:

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

Eine Anmerkung zu dieser while readSchleife, da Sie gefragt haben.

Erstens read -rist ohne Variablenname keine gültige shSyntax. Die shSyntax wird durch POSIX (ISO 9945, auch IEEE Std 1003.1) festgelegt, so wie die CSyntax durch ISO 9899 festgelegt ist.

Indiese Spezifikation, werden Sie feststellen, dass readein Variablennamen-Argument erforderlich ist. Das Verhalten, wenn Sie es weglassen, istnicht spezifiziertund variieren in der Praxis je nach shInterpreterimplementierung.

bashist der GNU- shInterpreter, ebenso gccwie der GNU C-Compiler. Beide bashhaben gccErweiterungen gegenüber den Vorgaben dieser Standards.

Im Fall von readwird so bashbehandelt read -r, als wäre es IFS= read -r REPLY. In der POSIX-Spezifikation IFS= read -r REPLYliest stdin, bis entweder ein \nZeichen oder das Ende der Eingabe erreicht ist, speichert die gelesenen Zeichen in der $REPLYVariablen und gibt mit einem zurückErfolgBeendigungsstatus, wenn ein Newline-Zeichen gelesen wurde (eine vollständige Zeile) oderVersagenandernfalls (wie EOF vor dem Zeilenumbruch) und lässt das Verhalten undefiniert, wenn die gelesenen Daten NUL-Zeichen oder Bytefolgen enthalten, die keine gültigen Zeichen bilden.

Im Fall von bashwerden die gelesenen Bytes gespeichert, auch wenn sie keine gültigen Zeichen bilden, und die NUL-Zeichen werden entfernt.

read -rist wie read -r REPLYin kshoder zshund meldet einen Fehler in yashoder ash-basierten POSIX-ähnlichen Shells.

Das Verhalten von echoist nicht angegeben, es sei denn, seine Argumente enthalten keine Backslash-Zeichen und das erste ist nicht -n.

Zusammenfassend shlässt sich also sagen, dass Sie nicht wissen, mit welcher Implementierung (und Version) Sie arbeiten,

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

reicht aus. Insbesondere im Fall von bashwird stdin nur so lange in der temporären Datei gespeichert, wie die Daten keine NUL-Zeichen enthalten, mit einem Zeilenumbruchzeichen enden und keine der Zeilen dem ^-[neE]+$erweiterten regulären Ausdruck entspricht (und/oder, je nach Umgebung oder Kompilierungsweise bashwie shbei OS/X, keine Backslash-Zeichen enthält).

Es ist auchsehr ineffizient und nicht die Art und Weise, wie Sie Text in Shells verarbeiten.

Hier möchten Sie:

cat > "$temp_file"

catist einStandardbefehl, das, wenn kein Argument angegeben wird, einfach seine Standardeingabe auf seine Standardausgabe ausgibtwie es ist.

verwandte Informationen