Search code examples
bashsshrsync

Bash script trouble interpretting input


I wrote a bash script that uploads a file on my home server. It gets activated from a folder action script using applescript. The setup is the folder on my desktop is called place_on_server. Its supposed to have an internal file structure exactly like the folder I want to write to: /var/www/media/ usage goes something like this:

  • if directory etc added to place_on_server: ./upload DIR etc
  • if directory of directory: etc/movies ./upload DIR etc movies //and so on
  • if file to place_on_server: ./upload F file.txt
  • if file in file in place_on_server ./upload F etc file.txt //and so on

for creating a directory its supposed to execute a command like:

ssh [email protected]<<EOF
cd /var/www/media/wherever
mkdir newdirectory
EOF

and for file placement:

rsync -rsh='ssh -p22' file  [email protected]:/var/www/media/wherever

script:

#!/bin/bash
addr=$(ifconfig -a | ./test)
if ($# -le "1")
then
    exit
elif ($1 -eq "DIR")
then
    f1="ssh -b root@$addr<<EOF"
    list = "cd /var/www/media\n"
    if($# -eq "2")
    then
        list=list+"mkdir $2\nEOF\n"
    else
        num=2
        i=$(($num))
        while($num < $#)
        do
            i=$(($num))
            list=list+"mkdir $i\n"
            list=list+"cd $i\n"
            $num=$num+1
        done
    fi
    echo $list
elif ($1 -eq "F")
then
    #list = "cd /var/www/media\n"
    f2="rsync -rsh=\'ssh -p22\' "
    f3 = "root@$addr:/var/www/media"
    if($# -eq "2")
    then
        f2=f2+$2+" "+f3
    else
        num=3
        i=$(($num))
        while($num < $#)
        do
            i=$(($num))
            f2=f2+"/"+$i
            $num=$num+1
        done
        i=$(($num))
        f2=f2+$i+" "+$f3
    fi
    echo $f2
fi
exit

output:

(prompt)$ ./upload2 F SO test.txt
./upload2: line 3: 3: command not found
./upload2: line 6: F: command not found
./upload2: line 25: F: command not found

So as you can see I'm having issues handling input. Its been awhile since I've done bash. And it was never extensive to begin with. Looking for a solution to my problem but also suggestions. Thanks in advance.


Solution

    1. For comparisons, use [[ .. ]]. ( .. ) is for running commands in subshells
    2. Don't use -eq for string comparisons, use =.
    3. Don't use < for numerical comparisons, use -lt
    4. To append values, f2="$f2$i $f3"
    5. To add line feeds, use $'\n' outside of double quotes, or a literal linefeed inside of them.
    6. You always need "$" on variables in strings to reference them, otherwise you get the literal string.
    7. You can't use spaces around the = in assignments
    8. You can't use $ before the variable name in assignments
    9. To do arithmetics, use $((..)): result=$((var1+var2))
    10. For indirect reference, such as getting $4 for n=4, use ${!n}
    11. To prevent word splitting removing your line feeds, double quote variables such as in echo "$line"

    Consider writing smaller programs and checking that they work before building out.

    Here is how I would have written your script (slightly lacking in parameter checking):

    #!/bin/bash
    addr=$(ifconfig -a | ./test)
    if [[ $1 = "DIR" ]]
    then
      shift
      ( IFS=/; echo ssh "root@$addr" mkdir -p "/var/www/media/$*"; )
    elif [[ $1 = "F" ]]
    then
      shift
      last=$#
      file=${!last}
      ( IFS=/; echo rsync "$file" "root@$addr:/var/www/media/$*" )
    else
      echo "Unknown command '$1'"
    fi
    

    $* gives you all parameters separated by the first character in $IFS, and I used that to build the paths. Here's the output:

    $ ./scriptname DIR a b c d
    ssh root@somehost mkdir -p /var/www/media/a/b/c/d
    $ ./scriptname F a b c d somefile.txt
    rsync somefile.txt root@somehost:/var/www/media/a/b/c/d/somefile.txt
    

    Remove the echos to actually execute.