Ocasionalmente, executo uma linha de comando do bash como esta:
n=0; while [[ $n -lt 10 ]]; do some_command; n=$((n+1)); done
Para correr some_command
várias vezes seguidas - 10 vezes neste caso.
Frequentemente some_command
é realmente uma cadeia de comandos ou um pipeline.
Existe uma maneira mais concisa de fazer isso?
let ++n
vez den=$((n+1))
(3 caracteres a menos).zsh
temrepeat 10 do some_command; done
.sh: 1: [[: not found
.Respostas:
Ou como uma linha única para aqueles que desejam copiar e colar facilmente:
fonte
for (n=0;n<k;n++))
pode ser melhor; Eu suspeito{1..k}
que materialize uma string com todos os números inteiros separados por espaços.n=15;for i in $(seq -f "%02g" ${n});do echo $i; done 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
Usando uma constante:
Usando uma variável (pode incluir expressões matemáticas):
fonte
x=10
for ((n=0; n < $x; n++));
for run in {1..10}; do echo "on run $run"; done
n
já estiver definido com um valor específico?for (( ; n<10; n++ ))
não funciona / edit: melhor, provavelmente, utilizar uma das outras respostas como awhile (( n++...
umOutra maneira simples de hackear:
executar eco 20 vezes.
Observe que a
seq 20 | xargs -Iz echo "Hi there z"
saída seria:fonte
seq 20
)seq 20 | xargs -I{} echo "Hi there {}"
z
não é um bom espaço reservado, porque é tão comum que pode ser um texto comum no texto de comando. O uso{}
será melhor.seq
? então seria só imprimirHi there
20 vezes (sem número)? EDIT: basta usar-I{}
e, em seguida, não tem nenhum{}
comandoIIIII
, então ele parece bom, por exemplo:seq 20 | xargs -IIIIII timeout 10 yourCommandThatHangs
Se você estiver usando o shell zsh:
Onde 10 é o número de vezes que o comando será repetido.
fonte
repeat 10 { !! }
Usando o GNU Parallel, você pode:
Se você não quiser o número como argumento e executar apenas um único trabalho por vez:
Assista ao vídeo de introdução para uma rápida introdução: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
Percorra o tutorial ( http://www.gnu.org/software/parallel/parallel_tutorial.html ). Você comanda a linha com amor por isso.
fonte
-j1 -N0
que desativam o paralelismo ????some_command
1000 vezes em série sem argumentos? E: você pode expressar isso mais curto queparallel -j1 -N0 some_command ::: {1..1000}
?repeat.sh repeatcount some_command
. Para implementação no shell script, eu poderia usarparallel
, se já estivesse instalado na máquina (provavelmente não seria). Ou posso gravitar em direção ao xargs, já que isso parece ser mais rápido quando nenhum redirecionamento é necessáriosome_command
.parallel -N0 -j1 --retries 4 --results outputdir/ some_command
Uma função simples no arquivo de configuração do bash (
~/.bashrc
geralmente) pode funcionar bem.Chame assim.
fonte
do ${*:2}
, adicionei evaldo eval ${*:2}
para garantir que funcionasse para executar comandos que não iniciam com executáveis. Por exemplo, se você deseja definir uma variável de ambiente antes de executar um comando comoSOME_ENV=test echo 'test'
.xargs
é rápido :Em um Linux moderno de 64 bits, fornece:
Isso faz sentido, pois o
xargs
comando é um único processo nativo que gera o/usr/bin/true
comando várias vezes, em vez dos loopsfor
ewhile
que são interpretados no Bash. Claro que isso só funciona para um único comando; se você precisar executar vários comandos em cada iteração do loop, será tão rápido, ou talvez mais rápido, do que passarsh -c 'command1; command2; ...'
para xargsTambém
-P1
pode ser alterado para, digamos,-P8
gerar 8 processos em paralelo para obter outro grande aumento de velocidade.Não sei por que o GNU paralelo é tão lento. Eu teria pensado que seria comparável ao xargs.
fonte
Outra forma do seu exemplo:
fonte
Por um lado, você pode agrupá-lo em uma função:
Chame assim:
fonte
tr
aqui é enganador e está trabalhando na saída demanytimes
, nãoecho
. Eu acho que você deve removê-lo da amostra.xargs e seq ajudarão
a vista :
fonte
Observe o sublinhado em vez de usar uma variável.
fonte
_
é um nome de variável.Se você fizer isso periodicamente, poderá executar o seguinte comando para executá-lo a cada 1 segundo indefinidamente. Você pode colocar outras verificações personalizadas para executá-lo n vezes.
watch -n 1 some_command
Se você deseja ter confirmação visual das alterações, acrescente
--differences
antes dols
comando.De acordo com a página do manual OSX, também há
A página do manual Linux / Unix pode ser encontrada aqui
fonte
Eu resolvi com esse loop, onde repeat é um número inteiro que representa o número do loop
fonte
Outra resposta: use a expansão de parâmetros em parâmetros vazios:
Testado em Centos 7 e MacOS.
fonte
Todas as respostas existentes parecem exigir
bash
e não funcionam com um BSD UNIX padrão/bin/sh
(por exemplo,ksh
no OpenBSD ).O código abaixo deve funcionar em qualquer BSD:
fonte
Um pouco ingênuo, mas é disso que geralmente me lembro de cima:
Muito semelhante à resposta de @ joe-koberg. O dele é melhor, especialmente se você precisar de muitas repetições, apenas é mais difícil me lembrar de outra sintaxe, porque nos últimos anos não estou usando
bash
muito. Quero dizer, não pelo menos para scripts.fonte
O arquivo de script
e a saída abaixo
fonte
E a forma alternativa
for
mencionada em (bashref) Construções em loop ?fonte
Pois loops são provavelmente o caminho certo para fazê-lo, mas aqui está uma alternativa divertida:
echo -e {1..10}"\n" |xargs -n1 some_command
Se você precisar do número da iteração como parâmetro para sua chamada, use:
echo -e {1..10}"\n" |xargs -I@ echo now I am running iteration @
Edit: Foi comentado corretamente que a solução fornecida acima funcionaria sem problemas apenas com execuções simples de comando (sem pipes, etc.). você sempre pode usar um
sh -c
para fazer coisas mais complicadas, mas não vale a pena.Outro método usado normalmente é a seguinte função:
rep() { s=$1;shift;e=$1;shift; for x in `seq $s $e`; do c=${@//@/$x};sh -c "$c"; done;}
agora você pode chamá-lo como:
rep 3 10 echo iteration @
Os dois primeiros números indicam o intervalo. O
@
será traduzido para o número da iteração. Agora você também pode usar isso com tubos:rep 1 10 "ls R@/|wc -l"
com o número de arquivos nos diretórios R1 .. R10.
fonte
rep 1 2 touch "foo @"
não criará dois arquivos "foo 1" e "foo 2"; em vez disso, cria três arquivos "foo", "1" e "2". Pode haver uma maneira de fazer a citação correta usandoprintf
e%q
, mas será complicado obter uma sequência arbitrária de palavras corretamente citadas em uma única sequência para a qual passarsh -c
.rep
no seu.bashrc
, outras invocações se tornam muito mais concisas.