How to handle filenames with dollar character ($) in bash?
I have managed to cobble together the following script that moves files from one Samba share to another. It seems to work for all legal windows filenames except when there is a dollar character ($) in the filename. Typical filename it fails on is: ~$file.doc
Any help would be appreciated.
#!/bin/bash
# Script to move old files from public to quarantine
srcbase=/net/public
destbase=/net/quarantine
logfile=$srcbase/moved.log
date > $logfile 2>1&
find $srcbase -noleaf -atime +30 -print0 | while IFS="" read -r -d "" file ; do
if [ -f "$file" ]; then
relname="${file#*$srcbase}"
destname="$destbase$relname"
destdir="$(dirname "$destname")"
if [ ! -d "$destdir" ]; then
cmd1="mkdir -p \""$destdir"\""
eval "$cmd1" >> $logfile 2>&1
fi
cmd="mv --backup=t -v \""$file"\" \""$destname"\""
eval "$cmd" >> $logfile 2>&1
if [ -e "$destname" ]; then
cmd2="touch -a \""$destname"\""
eval "$cmd2" >> $logfile 2&g开发者_如何学Got;&1
fi
fi
done
date >> $logfile 2>1&
echo Deleting empty directories from "$srcbase" >> $logfile 2>&1
find "$srcbase" -type d -empty -delete >> $logfile 2>&1
Of course you are. You're using eval
.
BASH FAQ entry #50
The problem probably comes from using the filenames in a variable that is evaled.
If you would use single quotes in the setup of the eval it prevents that the $ is interpreted there e.g.:
cmd2="touch -a '$destname'"
The $destname
is still replaced when cmd is created.
BUT: I'll advise strongly against building evals from filenames you find on a filesystem. This is a huge backdoor. e.g.: what if some prankster creates a file name ; rm -rf /
on the source filesystem?
Explanation of the security issues with eval
Your problem is your use of eval
. I recommend against it since it's very, very rarely necessary and extremely difficult to use. I don't see any need for it in your case
If you replace the contents of your loop with this
if [ -f "$file" ]; then
relname="${file#*$srcbase}"
destname="$destbase$relname"
destdir="$(dirname "$destname")"
if [ ! -d "$destdir" ]; then
mkdir -p "$destdir" >> $logfile 2>&1
fi
mv --backup=t -v "$file" "$destname"
if [ -e "$destname" ]; then
touch -a "$destname" >> $logfile 2>&1
fi
fi
It should work just as well, even with $ in the file name.
Did you find that this was not the case?
精彩评论