Comment exécuter une commande plusieurs fois en utilisant le shell bash?


153

Existe-t-il un moyen d'exécuter une commande (par exemple ps aux|grep someprocess) pendant n fois?

Quelque chose comme:

run -n 10  'ps aux|grep someprocess'

Je veux l'utiliser de manière interactive, veuillez ne pas poster de scripts.

Mise à jour: La raison pour laquelle je pose cette question est que je travaille sur de nombreuses machines et que je ne souhaite pas importer tous les scripts adaptés, etc., dans chaque boîte pour que les mêmes fonctionnalités soient appliquées à toutes les machines.


Réponses:


197

Je ne pense pas qu'il existe une commande ou un shell intégré, car il s'agit d'un sous-ensemble trivial de la forconception de la boucle du shell Bourne . Il est donc très simple de mettre en œuvre une telle commande.

Pour commencer, vous pouvez utiliser une forboucle factice :

for i in `seq 10`; do command; done

Ou, de manière équivalente, selon la suggestion de JimB, en utilisant Bash intégré pour générer des séquences:

for i in {1..10}; do command; done

Cela s'exécute dix fois à commandchaque exécution - il peut s'agir d'un tuyau ou d'une série de commandes séparées par ;ou &&. Vous pouvez utiliser la $ivariable pour savoir à quelle itération vous appartenez.

Si vous considérez cela comme un script et que, pour une raison non spécifiée (mais peut-être valide), vous pouvez l'implémenter en tant que commande, par exemple, sur votre .bashrc (non testé):

#function run
run() {
    number=$1
    shift
    for i in `seq $number`; do
      $@
    done
}

Usage:

run 10 command

Exemple:

run 5 echo 'Hello World!'

16
@mahatmanich, une boucle n'est pas un script. Rien ne vous empêche d’utiliser pour ... sur un terminal interactif.
Zoredache

3
Eh bien, le modèle ci-dessus est le type de méthode standard pour le faire et il est assez simple. Pourquoi n'est-ce pas bon pour toi? Peut-être que vous posez la mauvaise question? Quel est le but principal de vos scripts ou de vos actions que vous souhaitez répéter plusieurs fois? Peut-être y a-t-il une meilleure solution si nous posons le problème différemment.
Patkos Csaba

6
@mahatmanich - for est le bash intégré pour les itérations.
JimB

3
@Eduardo Ivanec - Pour votre information, bash a une gamme seq{1..10}
intégrée

1
Il semble que la séquence de crochets intégrée ne prend pas en charge la substitution de variable (voir stackoverflow.com/a/3737773/713554 ). La fonction que vous avez donnée fonctionne parfaitement .bashrcsi elle {1..$number} est remplacée par celle-ci `seq $number`.
Leo

29

ps aux | grep someprocesson dirait que vous voulez regarder les changements d'un programme pendant un temps fixe. Eduardo a donné une réponse qui répond à votre question avec précision, mais il existe une alternative watch:

watch 'ps aux | grep someprocess'

Notez que j'ai mis la commande entre guillemets pour éviter que le shell n'interprète la commande comme "exécutez watch ps aux" et dirige le résultat grep someprocess. Une autre façon de faire la commande précédente serait:

watch ps aux \| grep someprocess

Par défaut, une watchactualisation toutes les deux secondes peut être modifiée à l'aide de l' -noption. Par exemple, si vous voulez avoir un intervalle de 1 seconde:

watch -n 1 'ps aux | grep someprocess'

21

Juste pour le fun

pgrep ssh ;!!;!!;!!;!!;!!;!!

Quelqu'un peut-il expliquer cela s'il vous plaît? Semble très intrigant.
Daniel Vartanov

4
; est juste un séparateur de commande. !! rejouer la dernière commande dans bash. Donc, lancez 'pgrep ssh' et rejouez-le 6 fois.
Piotr Kukielka

Bien que ce soit instructif, ce n’est pas très intuitif. One-Liner forsemble être la meilleure solution. En tout cas merci pour la réponse.
erm3nda

1
cmd ;!!Sur une ligne, ne répétez- vous pas simplement la commande entrée avant la ligne actuelle? Il faudrait deux historyentrées distinctes .
Joel Purra

remplacez ;par &&pour vous arrêter au premier échec.
user881300

16

semblable aux réponses précédentes, mais ne nécessite pas la boucle for:

seq 10 | xargs -I -- echo "hello"

diriger la sortie de seq vers xargs sans arguments ni options


2
Cela ne fera qu'une exécution echo "hello" 1 2 3 4 5 6 7 8 9 10. Vous devez exécuter xargs avec -n 1pour un processus pour chaque entrée (nombre) et avec -P 10pour une exécution en parallèle (10 processus parallèles). En finissant avec seq 10 | xargs -n 1 -P 10 echo.
Alexander Klimetschek

16

Essaye ça:

yes ls | head -n5 | bash

Cela nécessite que la commande soit exécutée dans un sous-shell, ce qui représente un léger inconvénient. YMMV. En gros, vous obtenez la commande "oui" pour répéter la chaîne "ls" N fois; tandis que "head -n5" termine la boucle à 5 répétitions. Le dernier canal envoie la commande au shell de votre choix.

Incidemment, les cshcoquilles ont une repeatcommande intégrée . Vous pouvez l'utiliser pour exécuter votre commande dans un sous-shell bash!


5

Manière POSIX

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04_01

x=10
while [ $x -gt 0 ]; do
    command
    x=$(($x-1))
done

qui pourrait bien sûr être transformé en une ligne:

x=10; while [ $x -gt 0 ]; do command; x=$(($x-1)); done

et semble être le moyen le plus portable, et donc moins susceptible de vous faire installer des programmes.

Les éléments suivants sont moins portables:

  • brace expansion {1..10}: spécifique à bash, et générera une énorme ligne si l'argument est grand
  • seq: GNU
  • yes: GNU

Et si vous en avez assez de la portabilité, considérez GNU parallel:

sudo apt-get install parallel
seq 100 | parallel echo {}

qui exécute des commandes en parallèle et a de nombreuses options intéressantes.

Voir aussi: https://stackoverflow.com/questions/169511/how-do-i-iterate-over-a-range-of-numbers-defined-by-variables-in-bash


GNU Parallel est conçu pour être très portable. sh, zsh, ksh, et bashsont tous bien supportés sur la plupart des plateformes. csh, tcsh, fisha un peu de soutien. L' utilisation que parallel --embedvous pouvez même créer un script qui peut facilement être déplacé vers un autre système qui ne dispose pas de parallèle GNU installé.
Ole Tange

2

Une mise en œuvre de la coquille de poisson de @ de-eduardo Ivanec runfonction ci - dessus

function run
  set number $argv[1]
  for i in (seq $number)
    eval $argv[2..-1]
  end
end

0

Ce serait 'regarder' - devrait faire partie de presque tous les systèmes Unix utilisant procps

Vous pouvez voir les changements de fs ou les mouvements intéressants dans un système. Par exemple,

watch "df -hP | grep /tmp" 

Il suffit de mettre vos commandes en argument (voir man watch)


Il y a déjà une réponse avec une montre ... voir ci-dessous à droite ...
mahatmanich

0

Sur macOS, vous pouvez utiliser la repeatcommande.

repeat 10 ps aux | grep someprocess
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.