$(<file)(działa również z `<file`) jest specjalnym operatorem powłoki Korna skopiowanym przez zshi 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 > fileotworzy się i obcina file), ale wtedy nic się nie dzieje. Więc
< file
Otwiera się filedo odczytu, ale wtedy nic się nie dzieje, ponieważ nie ma polecenia. Więc to filejest zamknięte i to wszystko. Gdyby $(< file)proste zastąpienie polecenia , rozwinęłoby się do zera.
W specyfikacji POSIX , w $(script), jeśli scriptskł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 ( <filelub 0< filenie <&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ń, zshuruchamia $READNULLCMD(domyślnie pager), a gdy są przekierowania wejściowe i wyjściowe, $NULLCMD( catdomyślnie), więc nawet jeśli $(<&3)nie jest to rozpoznawane jako specjalne operator nadal będzie działał tak jak w tym kshprzypadku, wywołując do tego pager (ten pager zachowuje się tak, jakby catjego 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 ai b(lub tylko bwtedy, gdy multiosopcja jest wyłączona), $(< a > b)by skopiować ado bi 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ę zshtylko 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 catbył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 $fileprzypisanie 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/mapfilemodule i tylko dla zwykłych plików), który działa również z plikami binarnymi.
Zauważ, że warianty oparte na pdksh kshmają 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, zsha bashnajlepiej ograniczyć się tylko do $(<file)unikania komentarzy i pamiętać, że modyfikacje dokonanych w nich zmiennych mogą, ale nie muszą zostać zachowane.
bashzinterpretuje to jakocat filename”, czy masz na myśli, że to zachowanie jest specyficzne dla zastępowania poleceń? Bo jeśli uruchomię< filenamesię sam, bash go nie wykręci. Nic nie wyświetli i nie wróci do monitu.