In bash, ksh93 and zsh, you can use the %q
escape for the printf
builtin.
#!/bin/bash
# also works in ksh93, zsh
setup_and_run() {
some_setup_commands
cat >>rerun.sh <<EOF
some_setup_commands
$(printf '%q ' "$@")
EOF
"$@"
}
In bash, you can use the printf -v
to write the output to a variable rather than to standard output.
#!/bin/bash
printf -v cmd '%q ' "$@"
setup_and_run() {
some_setup_commands
cat >>rerun.sh <<EOF
some_setup_commands
$cmd
EOF
"$@"
}
In zsh, there's a different method which is the q
parameter expansion flag, followed by j: :
to join the array elements with a space.
#!/bin/zsh
setup_and_run() {
some_setup_commands
cat >>rerun.sh <<EOF
some_setup_commands
${(j: :)${(q)@}}
EOF
"$@"
}
In plain sh, it's more difficult. A reliable way to quote a word is to put single quotes around it, and replace each single quote inside by '\''
. Making the replacement correctly is not very easy, involving either an external call to sed or a loop.
#!/bin/sh
quote_simple_command () {
quoted=
for raw in "$@"; do
quoted="$quoted'"
while case "$raw" in *\'*) true;; *) false;; esac; do
quoted="$quoted${raw%%\'*}'\\''"
raw="${raw#*\'}"
done
quoted="$quoted$raw' "
done
printf %s "${quoted% }"
}
setup_and_run() {
some_setup_commands
cat >>rerun.sh <<EOF
some_setup_commands
$(quote_simple_command "$@")
EOF
"$@"
}
You can use a for loop:
for iteration in 10 100 1000 10000 100000; do
python -W ignore Experiment.py --iteration "${iteration}"
done
If you have multiple parameters, and you want all the various permutations of all parameters, as @Fox noted in a comment below, you can use nested loops. Suppose, for example, you had a --name
parameter whose values could be n1
, n2
, and n3
, then you could do:
for iteration in 10 100 1000 10000 100000; do
for name in n1 n2 n3; do
python -W -ignore Experiment.py --iteration "${iteration}" --name "${name}"
done
done
You could put that in a file, for example runExperiment.sh
and include this as the first line: #!/bin/bash
. You could then run the script using either:
bash runExperimen.sh
Or, you could make the script executable, then run it:
chmod +x runExperiment.sh
./runExperiment.sh
If you're interested in some results before others, that'll guide how you structure the loops. In my example above, the script will run:
... --iteration 10 --name n1
... --iteration 10 --name n2
... --iteration 10 --name n3
... --iteration 100 --name n1
So it runs all experiments for iteration 10 before moving on to the next iteration. If instead you wanted all experiments for name n1
before moving on to the next, you could make the name loop the "outer" loop.
for name in ...; do
for iteration in ...; do
Best Answer
When you run
what happens is that bash interprets the argument
$14
as$1
and4
separately. It then expands$1
(which in this case is equal to "1"), then appends the string4
to it, which results in "14". Although that was the result you were expecting, it's actually a side effect from Bash's actual behaviour. Like @steeldriver mentioned in comments, running your script like this instead :and then calling
echo $14
won't output "n" but "a4".Note that wrapping the variable in double-quotes :
will still not expand the variable correctly in Bash. The standard method is to use curly braces around the variable name :
For more information, see the official documentation for parameter expansion in Bash. It can do a lot more cool things too, like
to capitalize argument no.14. Give it a read! :)