POSIX compliant shell script does not support arrays except the positional parameters array.
Background:
In the main script, several case
conditions require running the same code with a different argument. Within the repeated code, it is necessary to to shift
the positional parameters.
#!/bin/sh
# /tmp/test.sh
case "$1" in
( *one* ) echo 1 ; shift ; echo 'more' ;;
( *two* ) echo 2 ; shift ; echo 'more' ;;
( *three* ) echo 3 ; shift ; echo 'more' ;;
( other ) echo 'other' ;;
( * ) :
esac
printf '[%s]\n' "$@"
Test it:
$ /tmp/test.sh 'arg one' '3 spaces' "with 'quotes'"
1
more
[3 spaces]
[with 'quotes']
To minimise code repetition (the actual code contains 10+ lines), how to wrap the similar case
condition codes into a function?
Trying to solve:
#!/bin/sh
# /tmp/test.sh
newline=$(printf '\n ')
newline=${newline% }
func() {
# Perform something based on arg $1.
# But do not echo here. echo here will mess up with the return value.
# Actual code do not echo here.
# echo "$1"
shift
shift
# Escape dangerous characters and preserve spaces
modified_args=""
for arg in "$@"; do
trailing_newlines=${arg##*[!"${newline}"]}
modified_args="${modified_args} '$(printf "%s" "$arg" | sed "s/'/'\\\\''/g")${trailing_newlines}'"
done
printf '%s' "$modified_args"
}
case "$1" in
( *one* ) args=$(func 1 "$@") ; eval set -- "$args" ;;
( *two* ) args=$(func 2 "$@") ; eval set -- "$args" ;;
( *three* ) args=$(func 3 "$@") ; eval set -- "$args" ;;
( other ) echo 'other' ;;
( * ) :
esac
printf '[%s]\n' "$@"
Test output:
$ newline=$(printf '\n ')
$ newline=${newline% }
$ /tmp/test.sh 'arg one' '3 spaces' '' "with 'quotes'" 'double "quote"' "$newline line two $newline line three $newline$newline"
[3 spaces]
[]
[with 'quotes']
[double "quote"]
[
line two
line three
]
- With a heads-up from @KamilCuk, I have made modifications to fix the issue of trailing newlines being trimmed.
It seems okay. But the concern is, if '$(printf "%s" "$arg" | sed "s/'/'\\\\''/g")'
escaping only the single quote safe enough?
I try to look into how getopt
does the escape.
It seems that getopt
only escape the single quote also, except when --shell tcsh
.
There is no sane way to manipulate the global value of
$@
from inside a function. My suggestion would be to refactor your code to avoid the repetitions by other means.Perhaps like this: