Thursday, August 7, 2014

BASH Shell: For Loop File Names With Spaces

http://www.cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html

BASH for loop works nicely under UNIX / Linux / Windows and OS X while working on set of files. However, if you try to process a for loop on file name with spaces in them you are going to have some problem. For loop uses $IFS variable to determine what the field separators are. By default $IFS is set to the space character. There are multiple solutions to this problem.

Set $IFS variable

Try it as follows:
#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for f in *
do
  echo "$f"
done
IFS=$SAVEIFS
OR
#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
# set me
FILES=/data/*
for f in $FILES
do
  echo "$f"
done
# restore $IFS
IFS=$SAVEIFS

More examples using $IFS and while loop

Now you know that if the field delimiters are not whitespace, you can set IFS. For example, while loop can be used to get all fields from /etc/passwd file:
....
while IFS=: read userName passWord userID groupID geCos homeDir userShell
do
      echo "$userName -> $homeDir"
done < /etc/passwd

Using old good find command to process file names

To process the output of find with a command, try as follows:
find . -print0 | while read -d $'\0' file
do
  echo -v "$file"
done
Try to copy files to /tmp with spaces in a filename using find command and shell pipes:
find . -print0 | while read -d $'\0' file; do cp -v "$file" /tmp; done

Processing filenames using an array

Sometimes you need read a file into an array as one array element per line. Following script will read file names into an array and you can process each file using for loop. This is useful for complex tasks:
#!/bin/bash
DIR="$1"
 
# failsafe - fall back to current directory
[ "$DIR" == "" ] && DIR="."
 
# save and change IFS 
OLDIFS=$IFS
IFS=$'\n'
 
# read all file name into an array
fileArray=($(find $DIR -type f))
 
# restore it 
IFS=$OLDIFS
 
# get length of an array
tLen=${#fileArray[@]}
 
# use for loop read all filenames
for (( i=0; i<${tLen}; i++ ));
do
  echo "${fileArray[$i]}"
done

Playing mp3s with spaces in file names

Place following code in your ~/.bashrc file:
mp3(){
 local o=$IFS
 IFS=$(echo -en "\n\b")
 /usr/bin/beep-media-player "$(cat  $@)" &
 IFS=$o
}
Keep list of all mp3s in a text file such as follows (~/eng.mp3.txt):
/nas/english/Adriano Celentano - Susanna.mp3
/nas/english/Nick Cave & Kylie Minogue - Where The Wild Roses Grow.mp3
/nas/english/Roberta Flack - Kiling Me Softly With This Song.mp3
/nas/english/The Beatles - Girl.mp3
/nas/english/John Lennon - Stand By Me.mp3
/nas/english/The Seatbelts, Cowboy Bebop - 01-Tank.mp3
To play just type:
$ mp3 eng.mp3.txt

No comments:

Post a Comment