tags:

views:

64

answers:

4

Hi,

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>&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
+2  A: 

You need to escape the $ character, like in my code below:

touch \$file
ls \$file
kogut
Which `$` should he be escaping?
Ignacio Vazquez-Abrams
This doesnt help in the case of the script since it creates the commandlines in the eval (questionably in itself). So this doen't answer the question at all.
Peer Stritzinger
+3  A: 

Of course you are. You're using eval.

BASH FAQ entry #50

Ignacio Vazquez-Abrams
+1 [BashFAQ/050](http://mywiki.wooledge.org/BashFAQ/050) is about avoiding putting commands in variables (applicable to the OP's code) and [BashFAQ/048](http://mywiki.wooledge.org/BashFAQ/048) is about the security issues of `eval` (also applicable).
Dennis Williamson
+1  A: 

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

Peer Stritzinger
+1, `eval` is a dangerous tool that needs to be handled with care.
DarkDust
+2  A: 

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?

Sorpigal