After reading about getting files with spaces in the name using find
, I put together a small code chunk to grab all .sh
files in a directory and make them executable:
find . -type f -name '*.sh' -print0 |
while IFS= read -r -d '' file; do
name=$(printf '%s\n' "$file" | sed "s|^\./||")
echo $name
if ! [[ -x $name ]] ; then
chmod +x "${name}"
fi
done
The third-to-last line gave me the most trouble. I went through all 3 permutations:
chmod +x $name
chmod +x ${name}
chmod +x "${name}"
I have two questions:
I'd like to know why the last one, and only the last one, worked. Does it have to do with the IFS
bit set earlier?
If there's a simpler way to do this, what would it be? Again, it should grab all .sh
files in the current directory -- all of which have spaces in their filenames -- and make them executable.
When you put a variable assignment at the beginning of a command, it only applies to that one command. So the IFS
you set earlier was only used by the read
command. The rest of the code uses the default IFS
, which has whitespace as the field separator.
If you want the IFS
setting to apply to all the code, you need to do it as a separate statement, not as a prefix of a command.
IFS=
find . -type f -name '*.sh' -print0 |
while read -r -d '' file; do
name=$(printf '%s\n' "$file" | sed "s|^\./||")
echo $name
if ! [[ -x $name ]] ; then
chmod +x "${name}"
fi
done
But in general you should quote your variables. Even if IFS
is set, you will have problems if the variable contains wildcard characters, because wildcards are expanded after expanding non-quoted variables. Only leave variables unquoted if you actually need word splitting and globbing.