This started as a post about shell arrays as means of maintaining filenames with spaces in them. Sadly, it fails at that. Still, compare two shell constructs:
$ egrep -li 'icon' $(find ~/src -type f -name '*.py' | egrep -v venv)
Against:
$ set -A python_files $(find ~/src -type f -name '*.py' | egrep -v venv)
$ for f in ${python_files[@]}; do egrep -li icon "${f}"; done
Note well that the second construct preserves whitespacing in filenames even if one where foolish enough to create a python program with whitespace in it’s filename.
I find myself doing the former a lot and there are a few places in my source code tree where there are embedded spaces in a directory. It’s probably time to retrain my finger memory to use the latter construct. This post comes because I find myself revisiting things occasionally. When people start with Unix, a common question is what’s the difference between $*, $@, "$*", and "$@"? This isn’t original work but here’s a shell script that answers the question.
$ cat foo.sh
#! /bin/bash
echo "## "'$*' -- expands elements
for arg in $*; do
echo "\"${arg}\""
done
echo
echo "## "'$@' -- expands elements
for arg in $@; do
echo "\"${arg}\""
done
echo
echo "## "'"$*"' -- all elements
for arg in "$*"; do
echo "\"${arg}\""
done
echo
echo "## "'"$@"'-- expands elements maintaining whitespace
for arg in "$@"; do
echo "\"${arg}\""
done
echo
exit 0
here’s what you get when you run the code:
$ /bin/bash foo.sh one two 'three four' five
## $* -- expands elements
"one"
"two"
"three"
"four"
"five"
## $@ -- expands elements
"one"
"two"
"three"
"four"
"five"
## "$*" -- all elements
"one two three four five"
## "$@"-- expands elements maintaining whitespace
"one"
"two"
"three four"
"five"
$
With arrays things are slightly different:
#! /bin/bash
## If Korn Shell -- set -A list "$@" also works
list=( "$@" )
echo "length: ........... ${#list[@]}"
echo "all elements: ..... ${list[@]}"
echo
for arg in "${list[@]}"; do
echo "\"${arg}\""
done
echo
exit 0
And the output when you run it:
$ /bin/ksh foo.sh one two 'three four' five
length: ........... 4
all elements: ..... one two three four five
"one"
"two"
"three four"
"five"
$ /bin/bash foo.sh one two 'three four' five
length: ........... 4
all elements: ..... one two three four five
"one"
"two"
"three four"
"five"
(venv) $ output
As above, sadly once you pipe the output of this into another program, in this case egrep -v ... to throw away the python that was pulled into your virtual environment, the spacis seems to get lost. Maybe some python can fix this?
