In the past you may have encountered this problem: looping through a list of files with a Bash “for loop” gave you headaches if filenames had spaces inside. This is our setting:
flevour@voyance:/tmp/blog_post$ touch "my filename with space"
flevour@voyance:/tmp/blog_post$ touch one two three other filenames
flevour@voyance:/tmp/blog_post$ ls -l
total 0
-rw-r--r-- 1 flevour flevour 0 2007-05-07 17:49 filenames
-rw-r--r-- 1 flevour flevour 0 2007-05-07 17:48 my filename with space
-rw-r--r-- 1 flevour flevour 0 2007-05-07 17:49 one
-rw-r--r-- 1 flevour flevour 0 2007-05-07 17:49 other
-rw-r--r-- 1 flevour flevour 0 2007-05-07 17:49 three
-rw-r--r-- 1 flevour flevour 0 2007-05-07 17:49 two
Now, the elite hacker that is in you wants to add a cool extension to all of these. Before getting your hands dirty with mv command, you cleverly echo the variables in the for loop so you know where you are going.
First try:
flevour@voyance:/tmp/blog_post$ for i in `ls`; do echo $i; done
filenames
my
filename
with
space
one
other
three
two
No luck. “Maybe”, you think, “I need to add the -1 (minus-one) switch to have each filename on a single line”, no luck anyway (feel free to try), The fact is Bash “for loop” parses input stream and stops as soon as it finds a “space”. Now if you surf a bit around you may find this solution that, although very compact and easy to remember, doesn’t satisfy your unconsciously deep need for deeper hackery hacknessity:
flevour@voyance:/tmp/blog_post$ ls | while read i; do echo $i; done
filenames
my filename with space
one
other
three
two
This solution correctly loops all the files. But I would like to show you a different approach that is obscure and great at the same time (found at LinuxQuestions):
flevour@voyance:/tmp/blog_post$ IFS=$'\n'
flevour@voyance:/tmp/blog_post$ for i in `ls`; do echo $i; done
filenames
my filename with space
one
other
three
two
Some remarks:
- it’s generally suggested to backup the original content of IFS and restore it when you don’t need the different value anymore
- IFS=$’\n’ looks strange to me, I don’t understand the need for the dollar sign. If you try with IFS=’\n’, you’ll get weird results. Any hackers out there can get the riddle an answer (Rionda? Riff Raff?)
- after some brief researches it’s not clear if IFS modification and restore is seen as a good programming pattern
- stands for Internal Field Separator
Of course the final script (we wanted to add extensions, remember?) would be:
flevour@voyance:/tmp/blog_post$ ifs=$IFS
flevour@voyance:/tmp/blog_post$ IFS=$'\n'
flevour@voyance:/tmp/blog_post$ for i in `ls`; do mv $i $i.1337; done
flevour@voyance:/tmp/blog_post$ IFS=$ifs
Enjoy your Bash hacking time!
Recent comments
1 week 6 days ago
3 weeks 5 days ago
6 weeks 5 days ago
6 weeks 6 days ago
6 weeks 6 days ago
7 weeks 1 day ago
7 weeks 2 days ago
7 weeks 3 days ago
10 weeks 5 days ago
12 weeks 3 days ago