Script doesn't work in loop but does if not

I have a script that only works if I remove it from the looping scenario.

#!/bin/bash

# Set the field seperator to a newline
##IFS="
##" 

# Loop through the file
##for line in `cat nlist.txt`;do

# put the line into a variable.
##dbuser=$line

echo "copying plugin..."


deststr="/home/admin/aname.mydomain.com/wp-content/plugins/wp-stuff"

movestr="cp -R -p /home/wp-stuff "$deststr
$movestr

echo "done"

##done

This works fine. But if I remove the ##'s and change aname to $dbuser then it fails with "no such file or directory"

Even if I remove the ##'s but hard code the aname in, it still fails exactly the same.

If I convert it so that it takes a command line argument, so that $dbuser is fed in each time, then it still works without the loop.

#!/bin/bash
 
EXPECTED_ARGS=1
dbuser=$1

deststr="/home/admin/"$dbuser".mydomain.com/wp-content/plugins/wp-stuff"

movestr="cp -R -p /home/wp-stuff "$deststr
$movestr

But as soon as I try to do it with the loop, I get the error.

Since if I hardcode it but leave it in the loop, it doesnt work, but if I hardcode but remove the looping mechanism, then it works fine.

I would really appreciate some simple help. I am not proficient at linux, so please go easy on me. I am using centos 5 if it makes a difference.

It would help to see at least the first few lines of your input .txt file. I'm guessing that it contains more than just the user name on each line. If that is the case then each space separated token on each record will be assigned to line and the loop executed. If your file contains three tokens per line (lets say a, b, and c for line 1), then the first time through the loop the deststr variable is assigned something like this:

/home/admin/a.mydomain.com/wp-content/plugins/wp-stuff

and that might not be a legitimate filename.

There are several ways that you can test for this, with the easiest being to echo the contents of deststr rather than executing the mv command. This would validate the contents of deststr and give you a better idea of what is going on.

If your input file does contain multiple columns of data, the following could be used to extract the proper column (column 3 in my example) and then do the right thing.

# Loop through the file; read and echo col 3 -- change $3 to which ever column you need
awk '{ print $3 }' <nlist.txt | while read dbuser
do
        echo "copying plugin..."
        #echo "($dbuser)"               # debugging if needed
        deststr="foo/home/admin/$dbuser.mydomain.com/wp-content/plugins/wp-stuff"

        cp -R -p /home/wp-stuff $deststr
done

If your input list contains only the dbuser name, then I suggest running your script with a 'set -x' at the top and looking at the tracing output for clues as to what is going on.

Hope this is useful.

Thanks for the response.

No, there is only one column of manually entered names. It is a simple text file and although it was about 250 lines long with legitimate subdomain names, I have manually reduced it to two for testing.

If I actually copy the screen output of the command that is echoed and repaste it as a single line, it works as well.

For example, it will display on the screen:

...
cp -R -p /home/wp-stuff /home/admin/aname.mydomain.com/wp-content/plugins/wp-stuff: No such file or directory

If I manually copy everything before the colon and paste it to a new line it works fine.

Here is an actual screen copy of me doing that, I have just changed the names for security.

-bash-3.2# ./clong.sh
copying plugin...
./clong.sh: line 23: cp -R -p /home/wp-stuff /home/admin/name1.mydomain.com/wp-content/plugins/wp-stuff: No such file or directory
done
copying plugin...
./clong.sh: line 23: cp -R -p /home/wp-stuff /home/admin/name2.mydomain.com/wp-content/plugins/wp-stuff: No such file or directory
done
-bash-3.2# cp -R -p /home/wp-stuff /home/admin/name2.mydomain.com/wp-content/plugins/wp-stuff
-bash-3.2#

As you can see, I copied the last line before the : (ctrl C) and repasted (mouse right click) it into the same ssh window and it worked without a hitch. (Yes the file copy worked, I checked.)

Other than me changing the subdomain and domain name here in this post, this is a ctrl C of the ssh screen and a ctrl V to here.

I really am baffled by this. The only things that I can come up with are;

  1. My bash is broken.
  2. The cat function is pulling in an invisible character that is screwing it up.

---------- Post updated at 02:27 PM ---------- Previous update was at 02:05 PM ----------

Here is the -x printout from the script.

-bash-3.2# ./clong.sh
+ IFS='
'
+ IFS='
'
++ cat nlist.txt
+ for line in '`cat nlist.txt`'
+ dbuser=name1
+ echo 'copying plugin...'
copying plugin...
+ deststr=/home/admin/name1.mydomain.com/wp-content/plugins/wp-stuff
+ movestr='cp -R -p /home/wp-stuff /home/admin/name1.mydomain.com/wp-content/plugins/wp-stuff'
+ 'cp -R -p /home/wp-stuff /home/admin/name1.mydomain.com/wp-content/plugins/wp-stuff'
./clong.sh: line 23: cp -R -p /home/wp-stuff /home/admin/name1.mydomain.com/wp-content/plugins/wp-stuff: No such file or directory
+ echo done
done
+ for line in '`cat nlist.txt`'
+ dbuser=name2
+ echo 'copying plugin...'
copying plugin...
+ deststr=/home/admin/name2.mydomain.com/wp-content/plugins/wp-stuff
+ movestr='cp -R -p /home/wp-stuff /home/admin/name2.mydomain.com/wp-content/plugins/wp-stuff'
+ 'cp -R -p /home/wp-stuff /home/admin/name2.mydomain.com/wp-content/plugins/wp-stuff'
./clong.sh: line 23: cp -R -p /home/wp-stuff /home/admin/name2.mydomain.com/wp-content/plugins/wp-stuff: No such file or directory
+ echo done
done
-bash-3.2#

You have set IFS to only split on a newline. After $movestr is expanded, there will not be any field splitting on the spaces within the string; it's just one long word to the shell.

Regards,
Alister

If I understand you correctly, you are saying that if the first line contains "word1 word2" etc that it is what is causing the problem.

My text file has ONE word per line.

My entire test file (nlist.txt) has two words in total, one on each line.

Also, if I copied and pasted what has failed if this were the case, why would it work?

If you feel that it is the case, how would I rectify this?

You do not understand me correctly.

The value of the IFS variable determines which characters are used to split the result of variable expansion. $movestr expands to the string "cp -R -p ...." and you have modified IFS so that it only splits that string on newlines. For that command to work properly, you need the shell to split on spaces as well .. perhaps tabs. In short, using the default value of IFS. Alternatively, you could use eval. The best solution, in this case, however, is to not use a for loop; use a while read loop and don't mess with IFS (at least not until you've had a chance to study its effects further).

You can confirm that this is the problem by storing the old value of IFS and restoring it before the line: $movestr

Demonstration:

$ cmd='echo hello world'
$ $cmd
hello world
$ IFS='
> '
$ $cmd
-bash: echo hello world: command not found

Thanks.

I had tried a while loop in the last 15 hours of frustration, but I must have done something else wrong because at the time it made no difference.

However, I tried it again as per your suggestion and it works.

The only caveat was that I had to put a new line at the end of the text list or it would fail to do the last one.

New and WORKING code :D:

#!/bin/bash

clear


 while read line
 do

dbuser=$line

echo "copying plugin..."


deststr="/home/admin/"$dbuser".mydomain.com/wp-content/plugins/wp-stuff"

movestr="cp -R -p /home/wp-stuff "$deststr
$movestr

echo "done"

done <"nlist.txt"