Register
It is currently Fri Sep 19, 2014 7:52 pm

Mac OS X and whitespaces


All times are UTC - 6 hours


Post new topic Reply to topic  [ 11 posts ] 
Author Message
 PostPosted: Sat Sep 25, 2010 7:28 pm   

Joined: Fri Sep 24, 2010 4:17 pm
Posts: 2
I am working in the Terminal app on a Mac machine running OS X Tiger.
In trying to teach myself the basics, I copied the following loop out of a book:
Code:
for i in $(ls -1 ~/Desktop/*.txt); do say -f $i; done

It worked as expected. So I decided to play around with it in different ways and came across a recurring problem.

Many filenames on a Mac contain spaces. When I renamed the text files on my Desktop to include spaces, the results of the loop did not come back as expected:
Code:
for i in $(ls -1 ~/Desktop/*.txt); do say -f $i; done
/Users/colpanic/Desktop/One: No such file or directory
NOTICE.txt: No such file or directory
/Users/colpanic/Desktop/Two: No such file or directory
README.txt: No such file or directory

The difficulty is the spaces in the filenames, "One NOTICE.txt" and "Two README.txt". I would appreciate if someone could show me how to rewrite the loop so it works with such filenames.

Thx in advance.


Top
 Profile  
 PostPosted: Sun Sep 26, 2010 12:27 am   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
noel44 wrote:
I am working in the Terminal app on a Mac machine running OS X Tiger.
In trying to teach myself the basics, I copied the following loop out of a book:
Code:
for i in $(ls -1 ~/Desktop/*.txt); do say -f $i; done


The difficulty is the spaces in the filenames, "One NOTICE.txt" and "Two README.txt". I would appreciate if someone could show me how to rewrite the loop so it works with such filenames.


There are 2 issues with the example:
First the 'ls' command will execute and return a list of files, including their spaces to the for-loop. The for-loop will see each word in the list it receives as an entry for it's loop. So a file with a space in it will be seen as 2 'words'. I still don't know why people do an 'ls' inside a for-loop, because many, if not all shells have file-globbing.
The second issue is that even if the variable 'i' will contain a filename with a space in it, it is passed without quotes to your 'say' command. The same happens here as described before. you will call the 'say' command with 2 separate 'words'. Both don't exist, except as a whole. If you want to pass a variable as a whole, please put double quotes around it.
So my solution would be:
Code:
for i in ~/Desktop/*.txt; do say -f "$i"; done


Top
 Profile  
 PostPosted: Sun Sep 26, 2010 1:28 pm   

Joined: Fri Sep 24, 2010 4:17 pm
Posts: 2
Thank you, Patsie

for both the explanation and the fix. It was just a throwaway example from a book I am working my way through but it sure bugged me to no end that I couldn't find a way to make it work. I am now... uh, relieved. With your help, I have a better understanding and a new tool in my belt going forward.

Thanks again for such a timely response,
noel44.


Top
 Profile  
 PostPosted: Tue Jan 04, 2011 4:55 pm   

Joined: Sun Apr 04, 2010 11:44 am
Posts: 9
I have a similar question with rm -r

I tried
Code:
for i in `ls`; do rm -r "$i"; done


but it still passes seperate words and I get

Code:
rm: cannot remove `VA-Coast': No such file or directory
rm: cannot remove `2': No such file or directory
rm: cannot remove `Coast': No such file or directory
rm: cannot remove `Power': No such file or directory
rm: cannot remove `Hour': No such file or directory
rm: cannot remove `(Mixed': No such file or directory
rm: cannot remove `By': No such file or directory
rm: cannot remove `DJ': No such file or directory
rm: cannot remove `NoPhrillz)-2010-MIXFIEND': No such file or directory


It seems to work with cp -r, why not with rm -r??


Top
 Profile  
 PostPosted: Tue Jan 04, 2011 11:38 pm   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
Patsie wrote:
First the 'ls' command will execute and return a list of files, including their spaces to the for-loop. The for-loop will see each word in the list it receives as an entry for it's loop. So a file with a space in it will be seen as 2 'words'. I still don't know why people do an 'ls' inside a for-loop, because many, if not all shells have file-globbing.


Use file-globbing in your for-loop and not 'ls'.


Top
 Profile  
 PostPosted: Wed Jan 05, 2011 9:34 am   

Joined: Sun Apr 04, 2010 11:44 am
Posts: 9
Please explain file-globbin. What i would like to do is to remove a list of directories that are already present in another directory:

Should i do it like this?

Code:
for i in /name_of_directory/*; do rm -r "$i"; done


The directories that have to be removed have whitespaces in their names


Top
 Profile  
 PostPosted: Wed Jan 05, 2011 10:46 am   
Moderator
User avatar

Joined: Wed May 03, 2006 2:05 pm
Posts: 242
That should work!

The other thing you could try is changing the internal field separator (IFS) temporarily so it doesn't split on whitespace. Something like this:

Code:
ls /path/to/directory/ | while IFS= read dirs; do rm -r /path/to/directory/"$dirs"; done


Top
 Profile YIM  
 PostPosted: Wed Jan 05, 2011 11:10 am   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
loetje wrote:
Please explain file-globbin. What i would like to do is to remove a list of directories that are already present in another directory:

Should i do it like this?

Code:
for i in /name_of_directory/*; do rm -r "$i"; done


The directories that have to be removed have whitespaces in their names


Yes this should work just fine. You are using file globbing right there :)
If you want to know more about file globbing, I suggest you read the wikipedia page


Top
 Profile  
 PostPosted: Wed Jan 05, 2011 5:17 pm   

Joined: Sun Apr 04, 2010 11:44 am
Posts: 9
Ok thanks guys this works! I deleted all the files in one directory based on the directories in another directory using this code

Code:
ls /path/to/directory/ | while IFS= read dirs; do rm -r ./"$dirs"; done


Thanks again


Top
 Profile  
 PostPosted: Wed Jan 05, 2011 6:40 pm   

Joined: Mon Mar 02, 2009 3:03 am
Posts: 546
Code:
for file in /path/to/directory/*
do if [ -d "$file" -a -d ./"${file##*/}" ]
   then rm -r ./"${file##*/}"
   fi
done


Top
 Profile  
 PostPosted: Thu Jan 13, 2011 4:47 pm   

Joined: Thu Jan 13, 2011 12:58 am
Posts: 6
Will that work for files in which name includes spaces?


Top
 Profile  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  


BashScripts | Promote Your Page Too
Powered by phpBB © 2011 phpBB Group
© 2003 - 2011 USA LINUX USERS GROUP