
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 ghc
als 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/stdin
die Standardeingabepipe (mit oder ohne Namen) genau wie eine benannte Pipe, d. h. das Programm könnte sie nicht /dev/stdin
von einer echten benannten Pipe unterscheiden.
Auf anderen Systemen ist es nicht genau dasselbe, aber tatsächlich /dev/stdin
erhalten 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 zsh
ist es einfach:
#! /bin/zsh -
"$@" =(cat)
Unter Linux und mit Shells, die gelöschte temporäre Dateien für Here-Dokumente verwenden (wie bash
und zsh
einige 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 read
Schleife, da Sie gefragt haben.
Erstens read -r
ist ohne Variablenname keine gültige sh
Syntax. Die sh
Syntax wird durch POSIX (ISO 9945, auch IEEE Std 1003.1) festgelegt, so wie die C
Syntax durch ISO 9899 festgelegt ist.
Indiese Spezifikation, werden Sie feststellen, dass read
ein Variablennamen-Argument erforderlich ist. Das Verhalten, wenn Sie es weglassen, istnicht spezifiziertund variieren in der Praxis je nach sh
Interpreterimplementierung.
bash
ist der GNU- sh
Interpreter, ebenso gcc
wie der GNU C-Compiler. Beide bash
haben gcc
Erweiterungen gegenüber den Vorgaben dieser Standards.
Im Fall von read
wird so bash
behandelt read -r
, als wäre es IFS= read -r REPLY
. In der POSIX-Spezifikation IFS= read -r REPLY
liest stdin, bis entweder ein \n
Zeichen oder das Ende der Eingabe erreicht ist, speichert die gelesenen Zeichen in der $REPLY
Variablen 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 bash
werden die gelesenen Bytes gespeichert, auch wenn sie keine gültigen Zeichen bilden, und die NUL-Zeichen werden entfernt.
read -r
ist wie read -r REPLY
in ksh
oder zsh
und meldet einen Fehler in yash
oder ash
-basierten POSIX-ähnlichen Shells.
Das Verhalten von echo
ist nicht angegeben, es sei denn, seine Argumente enthalten keine Backslash-Zeichen und das erste ist nicht -n
.
Zusammenfassend sh
lä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 bash
wird 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 bash
wie sh
bei 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"
cat
ist einStandardbefehl, das, wenn kein Argument angegeben wird, einfach seine Standardeingabe auf seine Standardausgabe ausgibtwie es ist.