Looping over commands to print and execute in BASH

Tag: bash Author: livislivis Date: 2009-07-13

In BASH, I want to do something like this:

#!/bin/bash                                                                     

HOST="blah"
USER="foo"
REMOTE_ROOT="${HOST}:~${USER}/"

REP_NAME=`basename $1`
TARGET_NAME="${REP_NAME}.git"

CMD1="git clone --bare $1 $TARGET_NAME"
CMD2="touch ${TARGET_NAME}/git-daemon-export-ok"
CMD3="scp -r $TARGET_NAME $REMOTE_ROOT"
CMD4="rm -rf $TARGET_NAME"

for i in {1..4}
do
  CMD="${CMD${i}}"
  echo "$CMD"
  `$CMD`
done

That is to say, I want to loop over a list of commands, display the command being executed, then execute it.

I don't know how to do the double dereferencing (CMD="${CMD${i}}" isn't legal in BASH).

Alternately, I'd be happy to do something like:

for CMD in "CMD1 CMD2 CMD3 CMD4"
do
  echo $$CMD
done

but of course that isn't the right syntax, either.

Best Answer

CMDS[1]="git clone --bare $1 $TARGET_NAME"
CMDS[2]="touch ${TARGET_NAME}/git-daemon-export-ok"
CMDS[3]="scp -r $TARGET_NAME $REMOTE_ROOT"
CMDS[4]="rm -rf $TARGET_NAME"

# ...

for x in 1 2 3 4
do
    ${CMDS[x]};
done

comments:

Of course. I'd just forgotten how to do arrays in bash. Thanks!

Other Answer1

Could you put your CMD's in an array instead?

Other Answer2

You want the ${!parameter} syntax, works in bash atleast. e.g.

#!/bin/sh

CMD1="ls"
CMD2="pwd"

for CMD in {CMD1,CMD2} ; do
    echo ${!CMD}
    ${!CMD}
done

Other Answer3

To do what you want use:

for i in 1 2 3 4; do
    eval cmd='$'CMD$i
    echo $cmd
    eval $cmd
done

For your alternate solution, you can use eval:

for CMD in CMD1 CMD2; do
    eval '$'$CMD
done

Other Answer4

y'all forgot seq(1). it takes three arguments: seq START INTERVAL END and produces a new line delimited list of between (inclusively) START and END, so you could do:

for i in `seq 1 1 4`
do
   echo...

also:

if a relative path is given after host:, it's assumed to be the login user's home directory. so you can just do:

REMOTE_ROOT="${HOST}:"

comments:

If you only want to increment by 1 you can shorthand it with seq 1 4

Other Answer5

This is more of a debugging/troubleshooting feature, and doesn't exactly answer your question, but I find it useful:

#!/bin/bash

# Enable command echoing
set -x 

pwd
uname -a

# Disable command echoing
set +x

echo 'Command echoing off now'

Example run:

~$ ./foo.sh 
+ pwd
/home/jason
+ uname -a
Linux jpc 2.6.26-2-amd64 #1 SMP Sun Jun 21 04:47:08 UTC 2009 x86_64 GNU/Linux
+ set +x
Command echoing off now
~$

Or if you had a similar file:

#!/bin/bash

pwd
uname -a

You could use bash -x to do the same thing without having to modify the file:

~$ bash -x ./bar.sh 
+ pwd
/home/jason
+ uname -a
Linux jpc 2.6.26-2-amd64 #1 SMP Sun Jun 21 04:47:08 UTC 2009 x86_64 GNU/Linux
~$

comments:

That isn't what I asked, but it is in fact a better way of doing what I wanted. Thanks!