LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 09-03-2009, 03:15 AM   #1
xaos5
Member
 
Registered: Dec 2004
Distribution: debian and slackware
Posts: 217

Rep: Reputation: 31
bash: 'find ./ -type d' how to deal with directories with spaces?


well here is my code:

problem is the line:
Code:
cd "$dir"
'find ./ -type d will return "/some dir", while cd expects "/some\ dir". I haven't a clue on how to fix this.

Code:
#!/bin/bash

root_dir=$(pwd)
if [ -z "$1" ]; then
	echo "Using current directory as base for scanning."
else
	root_dir="$1"	
fi

cd "$root_dir"
for dir in "$(find ./ -type d)"; do
	
	echo "Moving into $dir"
	cd "$dir"
	for i in "$(ls *.m4a 2>/dev/null)"; do
		echo -e "\tConverting $i to ${i%.m4a}.mp3"
		faad -q -o - "$i" | lame -h - "${i%.m4a}.mp3" &> /dev/null
		if [ $? -ne 0 ]; then
			echo "ERROR: Failed to execute script, see above for more Details."
			break
		fi
	done
	cd "$root_dir"
done
 
Old 09-03-2009, 03:27 AM   #2
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
Code:
for dir in "$(find ./ -type d)"; do
If you put double quotes around the command substitution, the result of the find command will be seen as a whole and the loop will be executed once, even if the list of directories is spanned across multiple lines. In any case, the best way I've found to deal with spaces in directory names is to use a while loop fed with a process substitution, that is something like this:
Code:
while read dir
do
  ls "$dir"
done < <(find ./ -type d)
Hope this helps!
 
Old 09-03-2009, 01:05 PM   #3
xaos5
Member
 
Registered: Dec 2004
Distribution: debian and slackware
Posts: 217

Original Poster
Rep: Reputation: 31
thanks that seemed to work, I did that on the inner loop also. I don't really understand how it works (I looked it up really quick)


here is the updated code if anybody is interested. It can be used in the current directory or a directory specified like ./scriptname /path/to/m4a files
Code:
#!/bin/bash

root_dir=$(pwd)
if [ -z "$1" ]; then
	echo "Using current directory as base for scanning."
else
	root_dir="$1"	
fi

cd "$root_dir"
#for dir in "$(find ./ -type d)"; do
while read dir; do
	echo "Moving into $dir"
	cd "$dir"
	#for i in "$(ls *.m4a 2>/dev/null)"; do
	while read i; do
		if [ -z "$i" ]; then
			continue
		fi
		echo -e "\tConverting $i to ${i%.m4a}.mp3"
		faad -q -o - "$i" | lame -h - "${i%.m4a}.mp3" &> /dev/null
		if [ $? -ne 0 ]; then
			echo "ERROR: Failed to execute script, see above for more Details."
			break
		fi
	done < <(ls *.m4a 2> /dev/null)
	cd "$root_dir"
done < <(find ./ -type d)
EDIT: NVM it doesn't work with more then one sub directory deep?

Last edited by xaos5; 09-03-2009 at 01:32 PM.
 
Old 09-03-2009, 01:55 PM   #4
xaos5
Member
 
Registered: Dec 2004
Distribution: debian and slackware
Posts: 217

Original Poster
Rep: Reputation: 31
ok fixed the issue above, seems $root_dir with the argument if it was a short path it failed when calling cd $root_dir within the sub directories. It now goes through directories in order instead of random.

here is the updated and hopefully working script:
Code:
#!/bin/bash

root_dir=$(pwd)
if [ -z "$1" ]; then
	echo "Using current directory as base for scanning."
else
	root_dir="$1"	
fi

cd "$root_dir"
if [ $? -ne 0 ]; then
	echo "Failed to find directory."
	return
fi

# get the full path
root_dir=$(pwd)

echo "Current Root Path: $root_dir"

#for dir in "$(find ./ -type d)"; do
while read dir; do
	echo "Moving into $dir"
	cd "$dir"
	#for i in "$(ls *.m4a 2>/dev/null)"; do
	while read i; do
		if [ -z "$i" ]; then
			continue
		fi
		echo -e "\tConverting to mp3: to $i" #${i%.m4a}.mp3"
		faad -q -o - "$i" | lame -h - "${i%.m4a}.mp3" &> /dev/null
		if [ $? -ne 0 ]; then
			echo "ERROR: Failed to execute script, see above for more Details."
			break
		fi
	done < <(ls *.m4a 2> /dev/null)
	cd "$root_dir"
done < <(find ./ -type d | sort)

Last edited by xaos5; 09-03-2009 at 01:56 PM.
 
Old 09-06-2009, 06:30 PM   #5
travishein
LQ Newbie
 
Registered: Apr 2004
Location: Canada
Posts: 11

Rep: Reputation: 0
Post More elegant way.

Not sure I like that nested while loop that takes input from the < after the block, at least I find it hard to read.


the script below, attempts to break this down to a single find loop, where we pipe its output into a while.

I additionally separated the iterate over directory part from the do operation part, so as to allow the iterate over directories with spaces logic to be reused.

Note the use of quotes everywhere. I also like to surround all variables with { } and end lines with ; , but that's just a preference thing.


Code:
#!/bin/bash

root_dir="$(pwd)";
if [ -z "${1}" ]; then
	echo "Using current directory as base for scanning.";
else
	root_dir="${1}";	
fi


if [ ! -d "${root_dir}" ]; then
	echo "Failed to find directory: ${root_dir}"
	exit 1;
fi

echo "Current Root Path: ${root_dir}";

# converts a single m4a file to a mp3 file
# storing the converted file in the same folder as the original
# but only if there does not already exist the output mp3 file
#
# parameter1: full path to the .m4a file
function convert_mp3() {
  in_file="${1}";
	parent_dir="$(dirname "${in_file}")";
	file_name="$(basename "${in_file}")";
	mp3_file="$(echo "${file_name}" | sed -e "s/\.m4a$/.mp3/")";
	out_file="${parent_dir}/${mp3_file}";
	if [ -f "${out_file}" ]; then
		echo "skipping already converted file ${in_file}, target .mp3 exists.";
	else
		faad -q -o - "${in_file}" | lame -h - "${out_file}" &> /dev/null;
		if [ $? -ne 0 ]; then
			echo "ERROR: Failed to execute convert ${in_file}, see above for more Details."
			exit 1;
		fi
		echo "converted ${in_file} => ${out_file}";
	fi;
}


# find all *.m4a files and calls the function to convert them to mp3 files
# works when the directories and/or files have spaces in them.
find "${root_dir}" -type f -name "*.m4a" | while read a_file; do
echo "${a_file}";
	convert_mp3 "${a_file}";
done;

Last edited by travishein; 09-06-2009 at 06:32 PM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
referencing directories with spaces in the names... bbneo Programming 7 06-23-2009 12:15 PM
samba: getting directories with spaces in its path genmaicha Linux - Software 1 06-02-2009 08:48 PM
Wine - changing directories with spaces blazintilda2005 Linux - Software 3 12-18-2005 03:05 PM
Bash Scripting Directories with Spaces gtwilliams Linux - Software 3 07-06-2005 03:16 PM
Directories with spaces Blitzkrieg Linux - General 4 11-28-2002 03:41 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 05:53 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration