$(<file)
(também trabalha com `<file`
) é um operador especial do shell Korn copiado por zsh
e bash
. Parece muito com substituição de comando, mas na verdade não é.
Nos shells POSIX, um comando simples é:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
Todas as peças são opcionais, você pode ter apenas redirecionamentos, apenas comandos, apenas atribuições ou combinações.
Se houver redirecionamentos, mas nenhum comando, os redirecionamentos serão executados (para que um > file
abra e trunque file
), mas nada acontece. assim
< file
Abre file
para leitura, mas nada acontece, pois não há comando. Então o file
é então fechado e é isso. Se $(< file)
fosse uma simples substituição de comando , ela se expandiria para nada.
Na especificação POSIX , em $(script)
, se script
consiste apenas em redirecionamentos, produz resultados não especificados . Isso é para permitir esse comportamento especial do shell Korn.
No ksh (testado aqui com ksh93u+
), se o script consistir em um e apenas um comando simples (embora os comentários sejam permitidos antes e depois) que consistem apenas em redirecionamentos (sem comando, sem atribuição) e se o primeiro redirecionamento for um stdin (fd 0) única entrada ( <
, <<
ou <<<
) de redireccionamento, de modo que:
$(< file)
$(0< file)
$(<&3)
(também $(0>&3)
, na verdade, o mesmo operador)
$(< file > foo 2> $(whatever))
mas não:
$(> foo < file)
- nem
$(0<> file)
- nem
$(< file; sleep 1)
- nem
$(< file; < file2)
então
- todos, exceto o primeiro redirecionamento, são ignorados (são analisados)
- e ele se expande para o conteúdo do arquivo / heredoc / herestring (ou qualquer outro conteúdo que possa ser lido no descritor de arquivo, se estiver usando coisas do tipo
<&3
), menos os caracteres de nova linha à direita.
como se estivesse usando, $(cat < file)
exceto que
- a leitura é feita internamente pela casca e não por
cat
- nenhum tubo ou processo extra está envolvido
- Como conseqüência do exposto acima, como o código interno não é executado em um subshell, qualquer modificação permanece posteriormente (como em
$(<${file=foo.txt})
ou $(<file$((++n)))
)
- erros de leitura (embora não sejam erros ao abrir arquivos ou duplicar descritores de arquivos) são ignorados silenciosamente.
Em zsh
, é o mesmo, exceto que esse comportamento especial só é acionado quando há apenas um redirecionamento de entrada de arquivo ( <file
ou 0< file
, não <&3
, <<<here
, < a < b
...)
No entanto, exceto ao emular outras conchas, em:
< file
<&3
<<< here...
é quando há apenas redirecionamentos de entrada sem comandos, fora da substituição de comando, zsh
executa o $READNULLCMD
(um pager por padrão) e quando há redirecionamentos de entrada e saída, o $NULLCMD
( cat
por padrão), portanto, mesmo que $(<&3)
não seja reconhecido como especial operador, ele ainda funcionará como se ksh
estivesse chamando um pager para fazê-lo (esse pager agindo como se cat
seu stdout fosse um canal).
No entanto, enquanto ksh
's $(< a < b)
se expandiria para o conteúdo a
, em zsh
, ele se expande para o conteúdo do a
e b
(ou apenas b
se a multios
opção for desativada), $(< a > b)
iria copiar a
para b
e expandir a nada, etc.
bash
tem um operador semelhante, mas com algumas diferenças:
comentários são permitidos antes, mas não depois:
echo "$(
# getting the content of file
< file)"
funciona mas:
echo "$(< file
# getting the content of file
)"
expande para nada.
como em zsh
, apenas um arquivo stdin redirecionamento, embora não há nenhuma volta queda a um $READNULLCMD
, por isso $(<&3)
, $(< a < b)
não executar os redirecionamentos mas expandir para nada.
- por algum motivo, embora
bash
não seja invocado cat
, ele ainda bifurca um processo que alimenta o conteúdo do arquivo através de um canal, tornando-o muito menos otimizador do que em outros shells. É como um local $(cat < file)
onde cat
seria construído cat
.
- Como conseqüência do exposto acima, qualquer alteração feita no interior é perdida posteriormente (no
$(<${file=foo.txt})
mencionado acima, por exemplo, essa $file
atribuição é perdida posteriormente).
Em bash
, IFS= read -rd '' var < file
(também funciona zsh
) é uma maneira mais eficaz de ler o conteúdo de um arquivo de texto em uma variável. Ele também tem o benefício de preservar os caracteres de nova linha à direita. Veja também $mapfile[file]
em zsh
(no zsh/mapfile
módulo e apenas para arquivos regulares) que também funciona com arquivos binários.
Observe que as variantes baseadas em pdksh ksh
têm algumas variações em comparação com o ksh93. De interesse, em mksh
(uma dessas conchas derivadas de pdksh), em
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
é otimizado, pois o conteúdo do documento here (sem os caracteres finais) é expandido sem que um arquivo ou canal temporário seja usado, como é o caso dos documentos here, o que o torna uma sintaxe eficaz de cotação de várias linhas.
Ser portátil para todas as versões de ksh
, zsh
e bash
, o melhor é limitar-se a $(<file)
evitar comentários e ter em mente que as modificações nas variáveis feitas dentro podem ou não ser preservadas.
bash
interpretará isso comocat filename
", você quer dizer que esse comportamento é específico para comandar a substituição? Porque, se eu correr< filename
sozinho, o bash não dá certo. Ele não produzirá nada e retornará a um prompt.