Eu gostaria de correr:
./a.out < x.dat > x.ans
para cada * .dat arquivo no diretório A .
Claro, isso poderia ser feito pelo script bash / python / qualquer que seja o tipo de script, mas eu gosto de escrever uma frase sexy. Tudo o que pude alcançar é (ainda sem nenhum stdout):
ls A/*.dat | xargs -I file -a file ./a.out
Mas -a no xargs não entende o arquivo de substituição de str.
Obrigado pela ajuda.
io-redirection
xargs
Nikolay Vyahhi
fonte
fonte
Respostas:
Primeiro de tudo, não use a
ls
saída como uma lista de arquivos . Use expansão de shell oufind
. Veja abaixo as possíveis consequências do uso indevido de ls + xargs e um exemplo dexargs
uso adequado .1. Maneira simples: para loop
Se você deseja processar apenas os arquivos abaixo
A/
, umfor
loop simples deve ser suficiente:2. pre1 Por que não
ls | xargs
?Aqui está um exemplo de quão ruim as coisas podem virar se você usar
ls
comxargs
para o trabalho. Considere um cenário a seguir:primeiro, vamos criar alguns arquivos vazios:
veja os arquivos e eles não contêm nada:
execute um comando mágico usando
xargs
:o resultado:
Então, você acabou de substituir ambos
mypreciousfile.dat
emypreciousfile.dat.ans
. Se houvesse algum conteúdo nesses arquivos, ele teria sido apagado.2. Usando
xargs
: da maneira correta comfind
Se você quiser insistir em usar
xargs
, use-0
(nomes terminados em nulo):Observe duas coisas:
.dat.ans
final;"
).Ambos os problemas podem ser resolvidos por diferentes formas de invocação de shell:
3. Tudo feito dentro
find ... -exec
Isso, novamente, produz
.dat.ans
arquivos e será interrompido se os nomes dos arquivos contiverem"
. Para fazer isso, usebash
e altere a maneira como é chamado:fonte
zsh
for usado como shell (e SH_WORD_SPLIT não estiver definido), todos os casos especiais desagradáveis (espaços em branco, "no nome do arquivo etc.) não precisam ser considerados. O trivialfor file in A/*.dat; do ./a.out < $file > ${file%.dat}.ans ; done
funciona em todos os casos.find
.Tente fazer algo assim (a sintaxe pode variar um pouco, dependendo do shell que você usa):
$ for i in $(find A/ -name \*.dat); do ./a.out < ${i} > ${i%.dat}.ans; done
fonte
somefile.dat.dat
e redirecionar toda a saída para um único arquivo.somefile.dat.ans
o material de saída não seria tão bom.-type file
seria bom (não pode< directory
), e isso torna a fada incomum do nome do arquivo triste.Para padrões simples, o loop for é apropriado:
Para casos mais complexos em que você precisa de outro utilitário para listar os arquivos (zsh ou bash 4 têm padrões suficientemente poderosos que você raramente precisa encontrar, mas se você deseja permanecer no shell POSIX ou usar o shell rápido como o traço, precisará encontrar qualquer coisa não trivial), enquanto a leitura é mais apropriada:
Isso manipulará espaços, porque a leitura é (por padrão) orientada a linhas. Ele não manipula novas linhas e não controla barras invertidas, porque, por padrão, interpreta sequências de escape (que na verdade permitem passar uma nova linha, mas a localização não pode gerar esse formato). Muitos shells têm a
-0
opção de ler, para que você possa lidar com todos os caracteres, mas infelizmente não é POSIX.fonte
Use o GNU Parallel:
Bônus adicional: você realiza o processamento em paralelo.
Assista aos vídeos de introdução para saber mais: http://www.youtube.com/watch?v=OpaiGYxkSuQ
fonte
Eu acho que você precisa de pelo menos uma invocação de shell no xargs:
Editar: Note-se que essa abordagem não funciona quando os nomes de arquivos contêm espaços em branco. Não pode trabalhar. Mesmo se você usasse find -0 e xargs -0 para fazer com que o xargs entendesse os espaços corretamente, a chamada do shell -c seria cortada por eles. No entanto, o OP pediu explicitamente uma solução xargs, e essa é a melhor solução xargs que eu criei. Se o espaço em branco nos nomes de arquivos for um problema, use find -exec ou um loop de shell.
fonte
ls
saída .ls
gera coisas como espaços sem escapar e esse é o problema.ls
não é bom. Masxargs
pode ser usado com segurança com o find - veja a sugestão 2 na minha resposta.Não há necessidade de complicar. Você poderia fazer isso com um
for
loop:o
${file%.dat}.ans
bit removerá o.dat
sufixo do nome do arquivo$file
e, em vez disso, adicionará.ans
ao final.fonte