O seguinte script Perl ( my.pl
) pode ser lido no arquivo args da linha de comando ou no STDIN:
while (<>) {
print($_);
}
perl my.pl
lerá de STDIN, enquanto perl my.pl a.txt
lerá de a.txt
. Isso é muito conveniente.
Quer saber se há um equivalente no Bash?
/proc/$$/fd/0
e/dev/stdin
? Notei que o último parece ser mais comum e parece mais direto.-r
ao seuread
comando, para que ele não coma acidentalmente\
caracteres; usewhile IFS= read -r line
para preservar os espaços em branco iniciais e finais./bin/sh
- você está usando um shell diferente debash
oush
?Talvez a solução mais simples seja redirecionar stdin com um operador de redirecionamento de mesclagem:
Stdin é o descritor de arquivo zero. O exemplo acima envia a entrada canalizada para o seu script bash para o stdin de less.
Leia mais sobre o redirecionamento de descritor de arquivo .
fonte
<&0
nesta situação - seu exemplo funcionará da mesma forma com ou sem ela - aparentemente, as ferramentas que você chama de dentro de um script bash por padrão veem o mesmo stdin que o próprio script (a menos que o script o consuma primeiro).Aqui está a maneira mais simples:
Uso:
Para atribuir stdin à variável, você pode usar:
STDIN=$(cat -)
ou simplesmenteSTDIN=$(cat)
como o operador não é necessário (conforme o comentário @ mklement0 ).Para analisar cada linha da entrada padrão , tente o seguinte script:
Para ler do arquivo ou stdin (se o argumento não estiver presente), você pode estendê-lo para:
Veja: Como ler stdin quando nenhum argumento é passado?no stackoverflow SE
fonte
[ "$1" ] && FILE=$1 || FILE="-"
paraFILE=${1:--}
. (Quibble: melhor evitar todos os-maiúsculas shell variáveis para colisões de nomes evitar com ambiente variáveis.)${1:--}
é compatível com POSIX, portanto deve funcionar em todos os shells semelhantes a POSIX. O que não funcionará em todos esses shells é a substituição do processo (<(...)
); funcionará no bash, ksh, zsh, mas não no traço, por exemplo. Além disso, é melhor adicionar-r
ao seuread
comando, para que ele não coma acidentalmente\
caracteres; precedaIFS=
para preservar os espaços em branco iniciais e finais.echo
: se uma linha consiste em-e
,-n
ou-E
, ela não será mostrada. Para corrigir isso, você deve usarprintf
:printf '%s\n' "$line"
. Eu não o incluí na minha edição anterior ... muitas vezes minhas edições são revertidas quando eu corrigo esse erro:(
.--
é inútil se primeiro argumento é'%s\n'
IFS=
comread
eprintf
nãoecho
.:)
.Eu acho que este é o caminho direto:
-
-
fonte
read
lê de stdin por padrão , então não há nenhuma necessidade para< /dev/stdin
.A
echo
solução adiciona novas linhas sempre queIFS
interrompe o fluxo de entrada. A resposta do @ fgm pode ser modificada um pouco:fonte
read
's comportamento: enquantoread
que potencialmente dividida em várias fichas pelos caracteres. contido em$IFS
, ele retornará apenas um único token se você especificar apenas um único nome de variável (mas, por padrão, apara e espaços em branco à esquerda e à direita).read
e$IFS
-echo
ele próprio adiciona novas linhas sem a-n
bandeira. "O utilitário echo grava todos os operandos especificados, separados por caracteres em branco (` ') e seguidos por um caractere de nova linha (`\ n') na saída padrão."\n
adicionada porecho
: O Perl$_
inclui a linha que termina\n
na linha lida, enquanto o bashread
não. (No entanto, como @gniourf_gniourf aponta em outro lugar, a abordagem mais robusta é usarprintf '%s\n'
em vez dissoecho
).O loop Perl na pergunta lê de todos os os argumentos de nome de arquivo na linha de comando ou da entrada padrão se nenhum arquivo for especificado. As respostas que vejo parecem processar um único arquivo ou entrada padrão se não houver um arquivo especificado.
Embora muitas vezes ridicularizado com precisão como UUOC (uso inútil de
cat
), há momentos em quecat
é a melhor ferramenta para o trabalho e é discutível que este seja um deles:A única desvantagem disso é que ele cria um pipeline em execução em um sub-shell, para que coisas como atribuições de variáveis no
while
loop não sejam acessíveis fora do pipeline. Abash
maneira de contornar isso é Substituição de Processo :Isso deixa o
while
loop em execução no shell principal, para que as variáveis definidas no loop sejam acessíveis fora do loop.fonte
>>EOF\n$(cat "$@")\nEOF
. Finalmente, uma queixa:while IFS= read -r line
é uma melhor aproximação do quewhile (<>)
faz no Perl (preserva os espaços em branco à esquerda e à direita - embora o Perl também mantenha a trilha\n
).O comportamento de Perl, com o código fornecido no OP, pode receber nenhum ou vários argumentos, e se um argumento é um único hífen,
-
isso é entendido como stdin. Além disso, sempre é possível ter o nome do arquivo$ARGV
. Nenhuma das respostas dadas até agora realmente imita o comportamento de Perl nesses aspectos. Aqui está uma possibilidade pura do Bash. O truque é usarexec
adequadamente.O nome do arquivo está disponível em
$1
.Se nenhum argumento for fornecido, definimos artificialmente
-
como o primeiro parâmetro posicional. Em seguida, fazemos um loop nos parâmetros. Se um parâmetro não for-
, redirecionamos a entrada padrão do nome do arquivo comexec
. Se esse redirecionamento for bem-sucedido, fazemos um loop com umwhile
loop. Estou usando aREPLY
variável padrão e, neste caso, você não precisa redefinirIFS
. Se você quiser outro nome, deverá redefinirIFS
assim (a menos, é claro, que não queira e saiba o que está fazendo):fonte
Mais precisamente...
fonte
IFS=
e-r
aoread
comando garante que cada linha seja lida sem modificação (incluindo espaços em branco à esquerda e à direita).Por favor, tente o seguinte código:
fonte
read
semIFS=
e-r
, e o pobre$line
sem suas citações saudáveis.read -r
notação. OMI, POSIX entendeu errado; a opção deve ativar o significado especial para as barras invertidas à direita, não desativá-lo - para que os scripts existentes (antes da existência do POSIX) não fossem interrompidos porque o-r
foi omitido. Observo, no entanto, que fazia parte da IEEE 1003.2 1992, que foi a versão mais antiga do padrão de shell e utilitários POSIX, mas foi marcada como uma adição até então, portanto, isso é uma chatice sobre oportunidades antigas. Eu nunca tive problemas porque meu código não usa-r
; Eu devo ter sorte. Me ignore nisso.-r
deve ser padrão. Concordo que é improvável que ocorra nos casos em que não usá-lo gera problemas. Porém, código quebrado é código quebrado. Minha edição foi desencadeada pela$line
variável pobre que perdeu muito as aspas. Eu consertei oread
tempo que estava nisso. Não corrigi oecho
porque esse é o tipo de edição que é revertida.:(
.O código
${1:-/dev/stdin}
entenderá apenas o primeiro argumento, então, que tal isso.fonte
Não acho nenhuma dessas respostas aceitável. Em particular, a resposta aceita apenas lida com o primeiro parâmetro da linha de comando e ignora o restante. O programa Perl que ele está tentando emular manipula todos os parâmetros da linha de comando. Portanto, a resposta aceita nem mesmo responde à pergunta. Outras respostas usam extensões bash, adicionam comandos desnecessários 'cat', funcionam apenas no caso simples de ecoar a entrada na saída ou são apenas desnecessariamente complicados.
No entanto, tenho que dar crédito a eles, porque eles me deram algumas idéias. Aqui está a resposta completa:
fonte
Combinei todas as respostas acima e criei uma função shell que atendesse às minhas necessidades. Isto é de um terminal cygwin das minhas 2 máquinas Windows10, onde eu tinha uma pasta compartilhada entre elas. Eu preciso ser capaz de lidar com o seguinte:
cat file.cpp | tx
tx < file.cpp
tx file.cpp
Onde um nome de arquivo específico é especificado, eu preciso usar o mesmo nome de arquivo durante a cópia. Onde o fluxo de dados de entrada foi canalizado, então eu preciso gerar um nome de arquivo temporário com a hora minutos e segundos. A pasta principal compartilhada possui subpastas dos dias da semana. Isso é para fins organizacionais.
Eis o script final para minhas necessidades:
Se houver alguma maneira de otimizar ainda mais isso, eu gostaria de saber.
fonte
O seguinte funciona com o padrão
sh
(Testado comdash
no Debian) e é bastante legível, mas isso é uma questão de gosto:Detalhes: se o primeiro parâmetro não estiver vazio,
cat
esse arquivo serácat
inserido como padrão. Em seguida, a saída de toda aif
instrução é processada pelocommands_and_transformations
.fonte
cat "${1:--}" | any_command
. Ler as variáveis shell e repeti-las pode funcionar para arquivos pequenos, mas não é tão dimensionável.[ -n "$1" ]
pode ser simplificado para[ "$1" ]
.Este é fácil de usar no terminal:
fonte
E se
fonte
cat
será colocada na linha de comando. A linha de comando tem um tamanho máximo. Além disso, isso não será lido linha por linha, mas palavra por palavra.