Sua união mágica é um ponto-e-vírgula ... e chaves:
{ cat wordlist.txt ; ls ~/folder/* ; } | wc -l
Os chavetas estão agrupando apenas os comandos, de modo que o sinal de |canal afeta a saída combinada.
Você também pode usar parênteses em ()torno de um grupo de comandos, que executaria os comandos em uma subshell. Isso tem um conjunto sutil de diferenças com chaves, por exemplo, tente o seguinte:
cd $HOME/Desktop ; (cd $HOME ; pwd) ; pwd
cd $HOME/Desktop ; { cd $HOME ; pwd ; } ; pwd
Você verá que todas as variáveis de ambiente, incluindo o diretório de trabalho atual, são redefinidas após a saída do grupo de parênteses, mas não após a saída do grupo de chaves.
Quanto ao ponto e vírgula, as alternativas incluem os sinais &&e ||, que executam condicionalmente o segundo comando somente se o primeiro for bem-sucedido ou não, respectivamente, por exemplo,
cd $HOME/project && make
ls $HOME/project || echo "Directory not found."
Isso funciona! Ajude-me a aprender - o que exatamente as chaves estão fazendo aqui? Que outros poderes mágicos eles têm?
David Oneill
@DavidOneill { list; }é um comando composto . From bash(1): list é simplesmente executado no ambiente atual do shell. A lista deve ser finalizada com uma nova linha ou ponto e vírgula. [..] O status de retorno é o status de saída da lista.
Lekensteyn
Adicionei um pouco mais de informação à resposta. O guia definitivo para scripts de shell com o bash é a página de manual do bash, digite man bashna linha de comando e procure-o.
Pablomme
deve o; nesses comandos não será && caso o arquivo wordlist.txt não exista?
Rinzwind
Se wordlist.txtnão existir, um erro de cataparecerá no erro padrão, mas não na saída padrão, portanto wc -l, não contará nenhuma linha a partir dele. O mesmo vale para ~/foldernão existir. Pode-se adicionar 2> /dev/nullentre cada um desses comandos e seu ponto e vírgula para evitar ruído no erro padrão, mas, além de feias, as mensagens de erro são inofensivas com a finalidade de contar as linhas.
Pablomme
8
Como wcaceita um caminho de arquivo como entrada, você também pode usar a substituição de processo:
Mente que ls ~/folder/*também retorna o conteúdo dos subdiretórios, se houver (devido à expansão glob). Se você quiser apenas listar o conteúdo ~/folder, use ls ~/folder.
O wc -lfoi apenas um exemplo inventado, na verdade estou colocando em algo mais complicado que não tem essa opção.
David Oneill
2
@DavidOneill Bem, como cataceita um argumento de arquivo, você pode usar cat <(cat wordlist.txt; ls wordlist.txt) | wc -le até cat wordlist.txt <(ls wordlist.txt) | wc -l. É claro que isso é muito feio, mas demonstra as infinitas possibilidades com as ferramentas de linha de comando.
Lekensteyn
1
@DavidOneill Correto, eu o corrigi agora, obrigado.
Lekensteyn
1
Você deseja ls ~/folder/que, se ~/folderfor um link simbólico, lsliste o conteúdo de seu destino em vez do próprio link. A propósito, todos os lscomandos devem ser seguidos -1para que um único arquivo por linha seja impresso e wc -lseja uma maneira válida de contar arquivos.
Pablomme
@ pablomme Você é verdadeiro sobre a coisa do link simbólico, mas -1está implícito, pois a saída não é um terminal, mas um tubo.
Lekensteyn
2
Eu estava me perguntando a mesma pergunta e acabei escrevendo um roteiro curto.
magicalUnionThing(Eu chamo append):
#!/bin/sh
cat /dev/stdin
$*
Tornar esse script executável
chmod +x ./magicalUnionThing
Agora você faz
cat wordlist.txt |./magicalUnionThing ls ~/folder/* | wc -l
O que faz:
Enviar entrada padrão para saída padrão
Executar argumento. $*retorna todos os argumentos como uma sequência. A saída desse comando vai para a saída padrão do script por padrão.
Portanto, o stdout do magicalUnionThing será o stdin + stdout do comando que é passado como argumento.
É claro que existem maneiras mais simples, como em outras respostas.
Talvez essa alternativa possa ser útil em alguns casos.
{ list; }
é um comando composto . Frombash(1)
: list é simplesmente executado no ambiente atual do shell. A lista deve ser finalizada com uma nova linha ou ponto e vírgula. [..] O status de retorno é o status de saída da lista.man bash
na linha de comando e procure-o.wordlist.txt
não existir, um erro decat
aparecerá no erro padrão, mas não na saída padrão, portantowc -l
, não contará nenhuma linha a partir dele. O mesmo vale para~/folder
não existir. Pode-se adicionar2> /dev/null
entre cada um desses comandos e seu ponto e vírgula para evitar ruído no erro padrão, mas, além de feias, as mensagens de erro são inofensivas com a finalidade de contar as linhas.Como
wc
aceita um caminho de arquivo como entrada, você também pode usar a substituição de processo:Isso equivale aproximadamente a:
Mente que
ls ~/folder/*
também retorna o conteúdo dos subdiretórios, se houver (devido à expansão glob). Se você quiser apenas listar o conteúdo~/folder
, usels ~/folder
.fonte
wc -l
foi apenas um exemplo inventado, na verdade estou colocando em algo mais complicado que não tem essa opção.cat
aceita um argumento de arquivo, você pode usarcat <(cat wordlist.txt; ls wordlist.txt) | wc -l
e atécat wordlist.txt <(ls wordlist.txt) | wc -l
. É claro que isso é muito feio, mas demonstra as infinitas possibilidades com as ferramentas de linha de comando.ls ~/folder/
que, se~/folder
for um link simbólico,ls
liste o conteúdo de seu destino em vez do próprio link. A propósito, todos osls
comandos devem ser seguidos-1
para que um único arquivo por linha seja impresso ewc -l
seja uma maneira válida de contar arquivos.-1
está implícito, pois a saída não é um terminal, mas um tubo.Eu estava me perguntando a mesma pergunta e acabei escrevendo um roteiro curto.
magicalUnionThing
(Eu chamoappend
):Tornar esse script executável
Agora você faz
O que faz:
$*
retorna todos os argumentos como uma sequência. A saída desse comando vai para a saída padrão do script por padrão.Portanto, o stdout do magicalUnionThing será o stdin + stdout do comando que é passado como argumento.
É claro que existem maneiras mais simples, como em outras respostas.
Talvez essa alternativa possa ser útil em alguns casos.
fonte