Como posso executar dois comandos em uma entrada, sem digitar essa entrada duas vezes?
Por exemplo, o comando stat diz muito sobre um arquivo, mas não indica seu tipo de arquivo:
stat fileName
O comando file indica o tipo de arquivo:
file fileName
Você pode fazer isso de uma linha desta maneira:
stat fileName ; file fileName
No entanto, você deve digitar o nome do arquivo duas vezes.
Como você pode executar os dois comandos na mesma entrada (sem digitar a entrada ou uma variável da entrada duas vezes)?
No Linux, eu sei canalizar saídas, mas como canalizar entradas?
command-line
Lonniebiz
fonte
fonte
<
(entrada do arquivo para o lado esquerdo) ou|
(entrada do fluxo para o lado direito). Há uma diferença.yank-last-arg
comando (atalho padrãoMeta-.
ouMeta-_
;Meta
geralmente sendo aAlt
tecla esquerda ) copiará o último parâmetro da linha de comando anterior para o atual. Portanto, após a execução,stat fileName
você digitafile [Meta-.]
e não precisa digitá-lofileName
novamente. Eu sempre uso isso.<
e>
é redirecionamento , não canalização . Um pipeline conecta dois processos, enquanto o redirecionamento simplesmente reatribui stdin / stdout.Respostas:
Aqui está outra maneira:
Exemplo:
Isso funciona em
bash
ezsh
. Isso também funcionamksh
e,dash
apenas, quando interativo. No AT&T ksh, isso só funciona quando ofile "$_"
está em uma linha diferentestat
daquela.fonte
!$
que não funciona porque se!$
expande para a última palavra do último evento histórico (portanto, da linha de comando inserida anteriormente, não do comando stat).Provavelmente vou acertar meus dedos por isso, aqui está uma combinação hacky de expansão e avaliação do bash brace que parece fazer o truque
fonte
csh
, nãobash
.bash
copiou deksh
. Esse código funcionará em todos os csh, tcsh, ksh, zsh, fish e bash.eval
? (referindo-se aos principais comentários)Com
zsh
, você pode usar funções anônimas:Com
es
lambdas:Você também pode fazer:
(fazendo o
stat
primeiro comofile
atualizará o tempo de acesso).Eu faria:
no entanto, é para isso que servem as variáveis.
fonte
{ stat -; file -;} < filename
é mágico.stat
deve estar verificando se o stdin está conectado a um arquivo e relatando os atributos do arquivo? Presumivelmente não avançar o apontador em stdin, portanto, permitindofile
aos conteúdos stdin Sniffstat -
dizstat
para fazer umfstat()
em seu fd 0.{ $COMMAND_A -; $COMMAND_B; } < filename
variante não funcionará no caso geral se $ COMMAND_A realmente ler qualquer entrada; por exemplo{ cat -; cat -; } < filename
, imprimirá o conteúdo do nome do arquivo apenas uma vez.stat -
é tratado especialmente desde o coreutils-8.0 (outubro de 2009), nas versões anteriores a isso você receberá um erro (a menos que você tenha um arquivo chamado-
de uma experiência anterior, nesse caso, obterá os resultados errados ...)stat -f0
.Todas essas respostas parecem scripts para mim, em maior ou menor grau. Para uma solução que realmente não envolve scripts e pressupõe que você esteja sentado ao teclado digitando em um shell, tente:
No bash, zsh e ksh, pelo menos, nos modos vi e emacs, pressionar Escape e sublinhado insere a última palavra da linha anterior no buffer de edição da linha atual.
Ou você pode usar a substituição do histórico:
No bash, zsh, csh, tcsh e a maioria dos outros shells,
!$
é substituído pela última palavra da linha de comando anterior quando a linha de comando atual é analisada.fonte
Esc _
? Você pode fazer o link com a documentação oficial?A maneira que descobri que isso é razoavelmente simples é usar xargs, ele pega um arquivo / pipe e converte seu conteúdo em argumentos de um programa. Isso pode ser combinado com o tee, que divide um fluxo e o envia para dois ou mais programas. No seu caso, você precisa:
Ao contrário de muitas das outras respostas, isso funcionará no bash e na maioria dos outros shells no Linux. Sugerirei que este é um bom caso de uso de uma variável, mas se você absolutamente não puder usá-lo, é a melhor maneira de fazê-lo apenas com pipes e utilitários simples (supondo que você não tenha um shell particularmente sofisticado).
Além disso, você pode fazer isso para qualquer número de programas, simplesmente adicionando-os da mesma maneira que esses dois após o tee.
EDITAR
Como sugerido nos comentários, existem algumas falhas nesta resposta, a primeira é o potencial de entrelaçamento de saída. Isso pode ser corrigido da seguinte maneira:
Isso forçará os comandos a serem executados alternadamente e a saída nunca será entrelaçada.
A segunda questão é evitar a substituição do processo que não está disponível em alguns shells, isso pode ser alcançado usando tpipe em vez de tee da seguinte forma:
Isso deve ser portátil para praticamente qualquer shell (espero) e resolver os problemas no outro elogio, no entanto, estou escrevendo este último na memória, pois meu sistema atual não possui o tpipe disponível.
fonte
ksh
(e não nas variantes de domínio público),bash
ezsh
. Observe questat
efile
será executado simultaneamente, portanto, possivelmente a saída deles será entrelaçada (suponho que você esteja usando| cat
para forçar o buffer de saída para limitar esse efeito?).Esta resposta é semelhante a algumas outras:
Diferente das outras respostas, que repetem automaticamente o último argumento do comando anterior, este requer que você conte:
Ao contrário de algumas das outras respostas, isso não requer aspas:
ou
fonte
Isso é semelhante a algumas das outras respostas, mas é mais portátil que esta e muito mais simples que esta :
ou
na qual
sh
está atribuído$0
. Embora haja mais três caracteres para digitar, esse (segundo) formulário é preferível, porque esse$0
é o nome que você atribui ao script embutido. É usado, por exemplo, em mensagens de erro do shell para esse script, como quandofile
oustat
não pode ser encontrado ou não pode ser executado por qualquer motivo.Se você quer fazer
para um número arbitrário de arquivos, faça
que funciona porque
"$@"
é equivalente a"$1" "$2" "$3" …
.fonte
$0
é o nome que você deseja atribuir a esse script embutido. É usado, por exemplo, em mensagens de erro do shell para esse script. Como quandofile
oustat
não pode ser encontrado ou não pode ser executado por qualquer motivo. Então, você quer algo significativo aqui. Se não for inspirado, basta usarsh
.Eu acho que você está fazendo uma pergunta errada, pelo menos para o que você está tentando fazer.
stat
efile
comandos estão recebendo parâmetros que são o nome de um arquivo e não o conteúdo dele. Mais tarde, é o comando que faz a leitura do arquivo identificado pelo nome que você está especificando.Um tubo deve ter duas extremidades, uma usada como entrada e outra como saída, e isso faz sentido, pois você pode precisar processar diferentes ao longo do caminho com ferramentas diferentes até obter o resultado necessário. Dizer que você sabe como canalizar saídas, mas não sabe como canalizar entradas não é correto em princípio.
No seu caso, você não precisa de um canal, pois é necessário fornecer a entrada na forma de um nome de arquivo. E mesmo que essas ferramentas (
stat
efile
) leiam stdin, o pipe não é relevante aqui novamente, pois a entrada não deve ser alterada por nenhuma ferramenta quando se trata da segunda.fonte
Isso deve funcionar para todos os nomes de arquivos no diretório atual.
fonte
}
... caracteres e não comece com-
. Algumasprintf
implementações (zsh, bash, ksh93) possuem a%q
. Comzsh
, isso pode ser:printf 'stat %q; file %1$q\n' ./* | zsh
sed
s///
eu acho, mas é sobre o escopo - e se as pessoas estão colocando isso em seus nomes de arquivos, devem usar o Windows.*
duas vezes . Você poderia muito bem dizerstat -- *; file -- *
.*
é expandida. A expansão de*
mais os dois comandos para cada argumento*
é a entrada. Vejo?printf commands\ %s\;shift *
Existem algumas referências diferentes para 'entrada' aqui, então darei alguns cenários com o entendimento em mente primeiro. Para sua resposta rápida à pergunta da forma mais curta :
O acima irá executar uma estatística no arquivo de teste, pegar (redirecionar) o seu STDOUT e incluir isso na próxima função especial (a parte <()), em seguida, produzirá os resultados finais do que quer que fosse, em um novo arquivo (arquivo de saída). O arquivo é chamado e, em seguida, referenciado com bash built-ins ($ 1 cada vez depois, até você iniciar um novo conjunto de instruções).
Sua pergunta é ótima e existem várias respostas e maneiras de fazer isso, mas isso realmente muda com o que você está fazendo especificamente.
Por exemplo, você pode repetir isso também, o que é bastante útil. Um uso comum disso é, na mentalidade do código psuedo, é:
Aceitar isso e expandir esse conhecimento permite criar coisas como:
Isso executará um simples ls -A em seu diretório atual e, em seguida, informará enquanto percorrer cada resultado do ls -A para (e é aqui que é complicado!) Grep "thatword" em cada um desses resultados, e somente realizará o anterior printf (em vermelho) se ele realmente encontrou um arquivo com "essa palavra". Ele também registrará os resultados do grep em um novo arquivo de texto, files_that_matched_thatword.
Exemplo de saída:
Tudo isso simplesmente imprimiu o resultado ls -A, nada de especial. Adicione algo para grep desta vez:
Agora, execute-o novamente:
Embora talvez seja uma resposta mais exaustiva do que você está procurando no momento, acredito que manter anotações úteis como essa ajudará muito mais em empreendimentos futuros.
fonte