Archived

This topic is now archived and is closed to further replies.

Sean99

question about bash "for" loop

Recommended Posts

I'm trying to write a bash script and havng trouble getting my "for" loop to parse the list the way I want it to. Here's what I want to do: I downloaded 24 files on a certain day, and I want to move every file with that date stamp to a different directory (there are about a hundred other files in this directory that have different created/modified dates). Now, I don't care that it isn't too time-consuming to move all 24 files manually, or whether or not the "mv" command can operate on specific dates (not sure if it can, I just don't care if it can or can't), or if there are any other easier methods to handle the movement of these 24 files. My curiosity has been piqued, so this has become a learning exercise for me rather than a goal to accomplish a practical job. The problem is that the file names contain spaces. My "for" statement looks like: for FILE in $(ls -l | grep "Apr 29" | cut -c 57-) # cut -c 57- cuts out only the file name from the listing do mv $FILE ../otherDirectory done The list that "for" operates on is parsed by white space, so it doesn't parse out full file names (every single one of these files contains at least one space). So then I tried to use "sed" to encapsulate file names in quotes before "for" starts assigning values to FILE: for FILE in $(ls -l | grep "Apr 29" | cut -c 57- | sed s/^/\"/g | sed s/$/\"/g) That seemed to indeed put quotes around file names, but FILE still got values parsed by spaces, even inside of quotes. For example, if I change the body of the loop to simply echo $FILE and I have the two files dated Apr 29: Jailhouse Rock.mp3 and Love Me Tender.mp3, I get the output: "Jailhouse Rock.mp3" "love Me Tender.mp3" I tried the same technique again, this time replacing the double quote marks with single quote marks, but I got the same result. Anybody know how I can properly create the list so that FILE can get assigned values containing spaces? Sean [Edit- noticed my "cut" commands were wrong] [edited by - Sean99 on May 1, 2003 2:08:48 PM] [edited by - Sean99 on May 1, 2003 6:17:21 PM]

Share this post


Link to post
Share on other sites
im not an expert with bash but i think if you use sed to escape the spaces ie if a file name is "abc 123.dfghy" use sed to make it "abc\ 123.dfghy" and for should treat the space as part of the filename and not a seperator.

Share this post


Link to post
Share on other sites
IIRC for always treats it''s list as a string and delimits by space. So even sed''n backslashes before the spaces will not help.

I know you didn''t want to hear this =), but most Nix admins would just use find with or ctime:

Assuming you want to get all files modified it the last 30 minutes:

find ./ -cmin -30 -type f -exec mv {} /your/new/directory/ \;

You can also just look into the other time comparison options and decide what to key off of.

Sorry it''s not a fix for your for loop, but to be honest, I''ve never tried to use for in for processing files. Find has plenty of options for parsing different directory depths and matching odds and ends vs a plain find.

The other thing you could do, though not sure if you would want to modify your file names, is to replace the space with some character, say a _.


  
for FILE in `ls -l | grep "Apr 29" | cut -c57- | sed -e "s/ /_/g"`
do
echo $FILE
done


I don''t like this though, especially since you have to bear in mind that the space between month and day is rjustified, so when you hit May 1, it''s actually "May 1" (2 spaces, not one). Just makes parsing by timestamp with grep a little more annoying.

Interim

Share this post


Link to post
Share on other sites
if escaping spaces doesnt work, can you explain this?
(Maybe we''ve got different shells/versions)

[kev82@zidane ~]$ for i in a\ b a\ c b\ c; do echo $i; done
a b
a c
b c
[kev82@zidane ~]$

Share this post


Link to post
Share on other sites
Not when you pass it as the result of a command like he was.

Try your same steps with `` or $().

he doesn''t know his strings before hand and they must be created by some script method.

There is probably way to get it in there, but to be honest, I never found a solid way and just stick to ''find'' in the real world (if you can call my job the real world.) =)

for example:

for FILE in `ls -l | cut -c48- | sed -e "s/ /\ /g"`
do
echo ${FILE}
done

Will result in:
Jailhouse
Rock.mp3
Love
Me
Tender.mp3

Same on Debian and OS X (BSD). Note the outputs are different, hence why I used 48 as my cut marker.

Let me know if you find a means to pass it to for and still have it retain it''s \.
Int.

Share this post


Link to post
Share on other sites