Click to See Complete Forum and Search --> : problem with for loop in BASH


Hayl
08-12-2003, 06:28 PM
i have some code to ftp all files in a directory using curl, and it is not doing what i am expecting.

i originally had this:
#!/bin/bash

for filename in "$(ls)" ; do
echo -e "Transferring : $filename\n"
curl -T $filename -u username:password ftp://server.com/public_html/
echo -e "\n"
done

and it worked except for an error when it hit a directory name - which i expected.

i wanted to stop it from attempting to ftp directories and give an error so i now have the following code:
#!/bin/bash

for filename in "$(ls)" ; do
if ! [ -d "$filename" ]; then
echo -e "Transferring : $filename\n"
curl -T $filename -u username:password ftp://server.com/public_html/
echo -e "\n"
fi
done

and it doesn't work.

i get this for output:
Transferring : images
index.html
nvidia.html
proftpd.html
ss1.html
ss2.html
ss3.html

curl: (6) Couldn't resolve host 'index.html'
curl: (6) Couldn't resolve host 'nvidia.html'
curl: (6) Couldn't resolve host 'proftpd.html'
curl: (6) Couldn't resolve host 'ss1.html'
curl: (6) Couldn't resolve host 'ss2.html'
curl: (6) Couldn't resolve host 'ss3.html'
curl: (25) Failed FTP upload: images: No such file or directory.

:confused: :confused: :confused:

sploo22
08-12-2003, 06:56 PM
I'm baffled too; but try changing the very first line to

#!/bin/bash -x

That should print out all of the commands that are executed, and maybe shed some more light on this problem.

Hayl
08-12-2003, 07:23 PM
it looks like it is trying to pass all the files in the directory at once instead of each one individually.

im sure it's a subtle syntax error of some sort.

hopefully bwkaz comes on soon - he will know what i am doing wrong :)


hmmm.... now my original code doesn't work. i must have changed something else.....

</me bangs head against wall>

sploo22
08-12-2003, 07:49 PM
Well, one thing you could do is replace $(ls) with * in your loop condition; I'm not sure if that would help, but it's worth a try. If you want to recurse through subdirectories, change it to $(find . -type f).

Hayl
08-12-2003, 09:10 PM
does the exact same thing unfortunately.

it's trying to put all the files at once sparated by a single space as the variable instead of each one separately and iterate through them.

Hayl
08-12-2003, 09:25 PM
for some odd reason, this works:#!/bin/bash

files=$(ls)
for filename in $files ; do
if ! [ -d "$filename" ]; then
echo -e "Transferring : $filename\n"
curl -T $filename -u username:password ftp://server.com/public_html/
echo -e "\n"
fi
done

if someone sees this and can tell me why the origianal code doesn't work and this does i'd be grateful.

Ath0s
08-12-2003, 09:34 PM
I think you need to remove the " from around the $(ls)

With the " it grabs the entire result at once, instead of seperating it into
individual files ...

Hope that helps,

(EDIT) I checked it with this simple script:

for i in "$(ls)"; do echo "next: $i"; done

compared to this:

for i in $(ls); do echo "next: $i"; done

Hayl
08-12-2003, 09:48 PM
ah cool! thanks. i'll try that later. i knew it was a simple syntax thing.

chrism01
08-13-2003, 11:03 AM
i always use

for files in `ls -1`

ie one file per line. Works just fine. :)

Hayl
08-13-2003, 11:22 AM
Originally posted by Hayl
ah cool! thanks. i'll try that later. i knew it was a simple syntax thing.

the final script - which now accepts options looks like this:
#!/bin/bash
# /usr/bin/ftp_directory
# Written by: DKD dale_d at telusplanet dot net
#
# Requires: curl
#
# Purpose: FTPs all files in the current directory to
# the specified server and path
#
# Usage: ftp_directory -f ftp://<servername>/<path>/ -u <username> -p <password>
# (NOTE: must have a trailing / on the path or curl will fail)
#
# Get user options
while getopts ":f:u:p:" opt;
do
case $opt in
f) ftp_server="$OPTARG" ;;
u) user_name="$OPTARG" ;;
p) password="$OPTARG" ;;
?) echo 'USAGE: ss.sh -i image_name -f ftp_server -u user_name -p password'
exit 1
esac
done

# iterate through all filenames in the current directory,
# skip subdirectories, use curl to ftp each file
for filename in $(ls) ; do
if ! [ -d "$filename" ]; then
echo -e "Transferring : $filename\n"
curl -T $filename -u $user_name:$password $ftp_server
echo -e "\n"
fi
done

CaptainPinko
10-04-2003, 03:21 AM
i'm just looking ata book and i'm trying to follow the syntax but
#! /usr/bin/bash

for CASH in 1.99 30.00 0.99 0.01
do
{
echo $CASH
}
done


doesn't do jack. thats pretty much the syntax in the book


for VAR in LIST
do
{ body }
done


am i missing something is that pretty much the same?

bwkaz
10-04-2003, 09:06 AM
bash is at /bin/bash, not /usr/bin/bash (your first line).

And I've never seen the curly braces before. They're definitely not needed (though I don't think they'd cause any problem).

CaptainPinko
10-04-2003, 01:26 PM
Originally posted by bwkaz
And I've never seen the curly braces before. They're definitely not needed (though I don't think they'd cause any problem).

reallllllly? my book has them everywhere....

and yeah i typed the wrong path at the top

bwkaz
10-04-2003, 05:15 PM
Check the bash manpage (though you'll have to search through it for quite a while...). Curly braces are only used to group commands (they act like parentheses, which execute the group of commands in a subshell, except they don't use a subshell).

But the "for" builtin doesn't need the loop body grouped at all; it executes every command between "do" and "done". Like I said, I don't think it'd mess anything up, it's just not strictly needed.

So I assume that once you fixed that path, the script worked? Because I can copy and paste it here, and it does...

CaptainPinko
10-05-2003, 12:31 AM
aye, it worked. i'm not quite sure which fixed it but it works now