241

Is there a way to run a command (e.g. ps aux|grep someprocess) for n times?

Something like:

run -n 10  'ps aux|grep someprocess'

I want to use it interactively.

Update: The reason I am asking this is, that I do work on a lot of machines and I don't want to import all my adaped scripts etc into every box to get the same functionality accross every machine.

mahatmanich
  • 2,954
  • 3
  • 22
  • 23

10 Answers10

321

I don't think a command or shell builtin for this exists, as it's a trivial subset of what the Bourne shell for loop is designed for and implementing a command like this yourself is therefore quite simple.

Per JimB's suggestion, use the Bash builtin for generating sequences:

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

For very old versions of bash, you can use the seq command:

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

This iterates ten times executing command each time - it can be a pipe or a series of commands separated by ; or &&. You can use the $i variable to know which iteration you're in.

If you consider this one-liner a script and so for some unspecified (but perhaps valid) reason undesireable you can implement it as a command, perhaps something like this on your .bashrc (untested):

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

Usage:

run 10 command

Example:

run 5 echo 'Hello World!'
mikemaccana
  • 3,370
  • 5
  • 25
  • 29
Eduardo Ivanec
  • 14,881
  • 1
  • 37
  • 43
  • simple for loop yap, but I said no scripts :-) – mahatmanich May 24 '11 at 16:00
  • 17
    @mahatmanich, A loop is not a script. There is nothing preventing you from using for... at an interactive terminal. – Zoredache May 24 '11 at 18:10
  • Yeh I guess I don't get around writing my own little script. I found the above before posting here at several websites on the net. – mahatmanich May 25 '11 at 06:35
  • @Zoredache yes I know it is not a script. however i find a forloop in this particular setting not the most simplistic approach. – mahatmanich May 25 '11 at 07:38
  • 3
    Well, the one-liner above is the kind of standard way to do it and it is fairly simple. Why is it not good for you? Maybe you are asking the wrong question? What is the main goal of your scripts or your actions that you want to repeat them a number of times? Maybe there is a better solution if we put the problem in a different way. – Patkos Csaba May 25 '11 at 08:43
  • Patkos I asked for a buildin tool that comes with the shell that does what I explained. Scripting that is no problem and I have done that before ... but it seems that the answer is "No there is no such tool" you must write a script to solve that problem. – mahatmanich May 25 '11 at 10:04
  • 6
    @mahatmanich - `for` *is* the bash built-in for iterating. – JimB May 25 '11 at 12:58
  • 4
    @Eduardo Ivanec - FYI, bash has built-in range like `seq`: `{1..10}` – JimB May 25 '11 at 13:03
  • @JimB - you're right, I tend to use `seq` as you it's more general but the question explicitly requested Bash. Thanks! – Eduardo Ivanec May 25 '11 at 15:04
  • @Eduardo '$@'in the function run() needs to be without '' -> $@ for it to work. – mahatmanich May 26 '11 at 12:40
  • @mahatmanich good catch, it was trying to execute the output of `command` that way. I corrected it. – Eduardo Ivanec May 26 '11 at 14:24
  • @Eduardo I know :-) but we don't need any command substitution there :-) thxs – mahatmanich May 26 '11 at 14:55
  • 1
    It seems the inbuilt bracket sequence does not support variable substitution (see http://stackoverflow.com/a/3737773/713554). The function you gave works perfectly when placed in `.bashrc` if `{1..$number} `is exchanged for `\`seq $number\`` though. – Leo Mar 29 '12 at 13:36
  • @mahatmanich - or anyone else - if this seems like a script to you, get a bigger screen and/or maximize your terminal window. – floer32 Aug 15 '13 at 11:38
  • +1 great script. any idea how do I pass two commands to run script. Example: run 3 "command1; command2" is not working when each command has more parameters inside. – Kostanos May 06 '14 at 17:35
44

ps aux | grep someprocess looks like you want to watch changes of a program for a fixed time. Eduardo gave an answer that answer your question exactly but there is an alternative: watch:

watch 'ps aux | grep someprocess'

Note that I've put the command in single quotes to avoid the shell from interpreting the command as "run watch ps aux" and pipe the result through grep someprocess. Another way to do the previous command would be:

watch ps aux \| grep someprocess

By default, watch refreshes every two seconds, that can be changed using the -n option. For instance, if want to have an interval of 1 second:

watch -n 1 'ps aux | grep someprocess'
Lekensteyn
  • 6,241
  • 6
  • 39
  • 55
28

Just for fun

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

NOTE: You must run the command pgrep ssh first, separately, and then enter the !!;!!;!!;!!;!!;!! string. Otherwise, the !! are replaced with the command that was previously executed.

; is a command separator and !! replay last command in bash. So this runs pgrep ssh and then replays it 6 times.

JESii
  • 103
  • 4
hdaz
  • 289
  • 3
  • 2
20

similar to previous replies, but does not require the for loop:

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

pipe output of seq to xargs with no arguments or options

nils-holmberg
  • 321
  • 2
  • 5
  • 4
    This will just do one execution `echo "hello" 1 2 3 4 5 6 7 8 9 10`. You need to run xargs with `-n 1` for one process for each input (number) and with `-P 10` for parallel execution (10 parallel processes). Ending up with `seq 10 | xargs -n 1 -P 10 echo`. – Alexander Klimetschek Apr 26 '17 at 22:08
19

Try this:

yes ls | head -n5 | bash

This requires the command to be executed in a sub-shell, a slight performance penalty. YMMV. Basically, you get the "yes" command to repeat the string "ls" N times; while "head -n5" terminated the loop at 5 repeats. The final pipe sends the command to the shell of your choice.

Incidentally csh-like shells have a built-in repeat command. You could use that to execute your command in a bash sub-shell!

Jakuje
  • 9,715
  • 2
  • 42
  • 45
android42
  • 191
  • 1
  • 2
11

On macOS you can use the repeat command.

repeat 10 ps aux | grep someprocess
Neil
  • 221
  • 2
  • 5
  • I am not seeing this command on Mac OS 10.15.7 - don't see it as a brew package either? – Patrick Steil Feb 25 '21 at 16:17
  • 2
    @PatrickSteil infact It's a zsh keyword http://zsh.sourceforge.net/Doc/Release/Shell-Grammar.html, ``` repeat word do list done word is expanded and treated as an arithmetic expression, which must evaluate to a number n. list is then executed n times. The repeat syntax is disabled by default when the shell starts in a mode emulating another shell. It can be enabled with the command ‘enable -r repeat’``` – Fangxing Apr 23 '21 at 09:24
  • In my case, I also had to wrap the output: `{ repeat 10 uuidgen } | clip` – Aleksander Stelmaczonek Jul 25 '22 at 16:10
9

POSIX way

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

which could of course be made into a one liner:

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

and seems to be the most portable way, and thus less likely to make you install programs.

The following are less portable:

  • brace expansion {1..10}: bash specific, and would generate a huge line if the argument is large
  • seq: GNU
  • yes: GNU

And if you get tired of portability, consider GNU parallel:

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

which runs commands in parallel and has many cool options.

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

  • GNU Parallel is built to be very portable. `sh, zsh, ksh`, and `bash` are all well supported on most platforms. `csh, tcsh, fish` has some support. Using `parallel --embed` you can even build a script that can easily be moved to another system which does not have GNU Parallel installed. – Ole Tange Dec 19 '18 at 00:35
3

A fish shell implementation of @eduardo-ivanec's run function above

function run
  set number $argv[1]
  for i in (seq $number)
    eval $argv[2..-1]
  end
end
chicks
  • 3,793
  • 10
  • 27
  • 36
masukomi
  • 101
  • 3
2

To run ps aux multiple times searching for a different known string each time:

for str in {str1,str2,...}; do ps aux | grep $str | grep -v " grep "; done

The grep -v " grep " part will remove grep itself from the result, which is a bad idea if one of your search strings is grep.

1

That would be 'watch' - should be part of almost every unix system using procps

You can see fs changes or otherwise interesting movement in a system. For example,

watch "df -hP | grep /tmp" 

Just put your commands as an argument (see man watch)

Andrew Schulman
  • 8,811
  • 21
  • 32
  • 47
Chris Arnu
  • 11
  • 1