$(<file)
(działa również z `<file`
) jest specjalnym operatorem powłoki Korna skopiowanym przez zsh
i bash
. Wygląda bardzo podobnie do zastępowania poleceń, ale tak naprawdę nie jest.
W powłokach POSIX proste polecenie to:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
Wszystkie części są opcjonalne, możesz mieć tylko przekierowania, tylko polecenia, tylko przypisanie lub kombinacje.
Jeśli istnieją przekierowania, ale nie ma polecenia, przekierowania są wykonywane (więc > file
otworzy się i obcina file
), ale wtedy nic się nie dzieje. Więc
< file
Otwiera się file
do odczytu, ale wtedy nic się nie dzieje, ponieważ nie ma polecenia. Więc to file
jest zamknięte i to wszystko. Gdyby $(< file)
proste zastąpienie polecenia , rozwinęłoby się do zera.
W specyfikacji POSIX , w $(script)
, jeśli script
składa się tylko z przekierowań, daje nieokreślone wyniki . To pozwala na to specjalne zachowanie skorupy Korna.
W ksh (tutaj testowane z ksh93u+
), jeśli skrypt składa się z jednego i tylko jednego prostego polecenia (chociaż komentarze są dozwolone przed i po), który składa się tylko z przekierowań (bez polecenia, bez przypisania) i jeśli pierwszym przekierowaniem jest stdin (fd 0) tylko wejście ( <
, <<
i <<<
) przekierowania sposób:
$(< file)
$(0< file)
$(<&3)
(również w $(0>&3)
rzeczywistości, ponieważ w rzeczywistości jest to ten sam operator)
$(< file > foo 2> $(whatever))
ale nie:
$(> foo < file)
- ani
$(0<> file)
- ani
$(< file; sleep 1)
- ani
$(< file; < file2)
następnie
- wszystkie oprócz pierwszego przekierowania są ignorowane (są analizowane)
- i rozwija się do zawartości pliku / heredoc / herestring (lub czegokolwiek, co można odczytać z deskryptora pliku, jeśli używa się takich rzeczy
<&3
), minus końcowe znaki nowego wiersza.
jakbyś za $(cat < file)
wyjątkiem tego
- odczyt jest wykonywany wewnętrznie przez powłokę, a nie przez
cat
- nie jest wymagana żadna rura ani dodatkowy proces
- w wyniku powyższego, ponieważ kod wewnątrz nie jest uruchamiany w podpowłoce, wszelkie modyfikacje pozostają później (jak w
$(<${file=foo.txt})
lub $(<file$((++n)))
)
- błędy odczytu (choć nie błędy podczas otwierania plików lub powielania deskryptorów plików) są dyskretnie ignorowane.
W zsh
, to samo z wyjątkiem tego, że szczególną zachowanie jest wyzwalany tylko wtedy, gdy istnieje tylko jeden plik wejściowy przekierowania ( <file
lub 0< file
nie <&3
, <<<here
, < a < b
...)
Jednak z wyjątkiem emulacji innych powłok, w:
< file
<&3
<<< here...
oznacza to, że istnieją tylko przekierowania wejściowe bez poleceń, poza podstawianiem poleceń, zsh
uruchamia $READNULLCMD
(domyślnie pager), a gdy są przekierowania wejściowe i wyjściowe, $NULLCMD
( cat
domyślnie), więc nawet jeśli $(<&3)
nie jest to rozpoznawane jako specjalne operator nadal będzie działał tak jak w tym ksh
przypadku, wywołując do tego pager (ten pager zachowuje się tak, jakby cat
jego standardowe wyjście było potokiem).
Jednak podczas gdy ksh
„s $(< a < b)
rozwinie się do treści a
, w zsh
, rozszerza się do treści a
i b
(lub tylko b
wtedy, gdy multios
opcja jest wyłączona), $(< a > b)
by skopiować a
do b
i rozwinąć do niczego, itd.
bash
ma podobny operator, ale z kilkoma różnicami:
komentarze są dozwolone przed, ale nie po:
echo "$(
# getting the content of file
< file)"
działa, ale:
echo "$(< file
# getting the content of file
)"
rozwija się do zera.
jak się zsh
tylko jeden plik stdin przekierowania, choć nie ma spaść z powrotem do $READNULLCMD
, tak $(<&3)
, $(< a < b)
nie wykonywać przekierowań ale poszerzyć do niczego.
- z jakiegoś powodu, mimo
bash
że nie wywołuje cat
, nadal rozwidla proces, który przekazuje zawartość pliku przez potok, dzięki czemu jest mniej optymalizacyjny niż w innych powłokach. Jest to w istocie niczym $(cat < file)
gdzie cat
byłaby wbudowane cat
.
- w wyniku powyższego wszelkie zmiany dokonane wewnątrz są następnie tracone (w
$(<${file=foo.txt})
wyżej wspomnianym na przykład $file
przypisanie jest tracone później).
W bash
, IFS= read -rd '' var < file
(działa także w zsh
) jest bardziej skuteczny sposób, aby odczytać zawartość tekstu pliku do zmiennej. Ma także tę zaletę, że zachowuje końcowe znaki nowego wiersza. Zobacz także $mapfile[file]
w zsh
(w zsh/mapfile
module i tylko dla zwykłych plików), który działa również z plikami binarnymi.
Zauważ, że warianty oparte na pdksh ksh
mają kilka odmian w porównaniu do ksh93. Interesujące w mksh
(jednej z tych powłok pochodzących z pdksh), w
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
jest zoptymalizowany pod tym względem, że zawartość tego dokumentu (bez znaków końcowych) jest rozszerzana bez użycia pliku tymczasowego lub potoku, jak ma to miejsce w przypadku dokumentów tutaj, co czyni go efektywną składnią wielowierszowego cytowania.
Aby być przenośnym dla wszystkich wersji ksh
, zsh
a bash
najlepiej ograniczyć się tylko do $(<file)
unikania komentarzy i pamiętać, że modyfikacje dokonanych w nich zmiennych mogą, ale nie muszą zostać zachowane.
bash
zinterpretuje to jakocat filename
”, czy masz na myśli, że to zachowanie jest specyficzne dla zastępowania poleceń? Bo jeśli uruchomię< filename
się sam, bash go nie wykręci. Nic nie wyświetli i nie wróci do monitu.