Welcome to the most active Linux Forum on the web.
Go Back > Forums > Linux Forums > Linux - Newbie
User Name
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!


  Search this Thread
Old 10-28-2009, 04:48 AM   #1
LQ Newbie
Registered: Oct 2009
Posts: 3

Rep: Reputation: 0
Bash pipe question

Hi there
I have the script

find -iname "*.mp3" | while read n; do
	echo $n | sed 's/.wav././' | sed 's/[0-9]*\ //' | sed 's/-//' |
        sed 's/\ -\ /*/' | sed 's/.mp3//' | sed 's/.\///' | while read k; do
    	      find -iname "*$k*";
My question is if I can avoid having the second loop? I would like to collect the output of the last sed command like j=`sed 's/.\///'`. Syntax doesn't allow this. If I put `` around the whole sequence of sed commands, I get something that looks like the accumulated output of all the seds.

Thank you

Last edited by Dalekk; 10-28-2009 at 04:56 AM. Reason: Code tags are messed up...
Old 10-28-2009, 05:17 AM   #2
Senior Member
Registered: Aug 2006
Posts: 2,697
Blog Entries: 5

Rep: Reputation: 244Reputation: 244Reputation: 244
describe what you are doing properly. Provide examples of files you are searching for, what you want to do with them, and your final output. the above definitely can be coded more efficiently.
Old 10-28-2009, 05:33 AM   #3
LQ Newbie
Registered: Oct 2009
Posts: 3

Original Poster
Rep: Reputation: 0
Well, I am in a situation where I have to rename a lot of files, and naturally I don't want to do this manually.

I have two groups of files. The first group is about 200 .mp3 files and the second group is about 100.000 files with lyrics from all sorts of music, including lyrics for the 200 .mp3 files. I want to make a third group containing the 200 .mp3 files and the 200 corresponding lyrics-files. The problem is that the naming of the .mp3 files follow different standards, with some being TRACK NUMBER - ARTIST - ALBUM - TITLE, some being TRACK NUMBER - TITLE and other combinations as well. The lyrics files are all ARTIST - ALBUM - TITLE.

I have the .mp3 file "01 - Dungen - Panda.mp3" and want to find the lyrics file
Dungen-Ta Det Lungt-2004-Panda.txt after which I want to rename the mp3 to Dungen-Ta Det Lungt-2004-Panda.mp3.

I have done this by first using sed to reform the .mp3 name to a string that can be used with find, and then use the string to search the lyrics directory.

My full code is:

find -iname "*.mp3" | while read n; do
    echo $n | sed 's/.wav././' | sed 's/[0-9]*\ //' | sed 's/-//' | sed 's/\ -\ /*/' | sed 's/.mp3//' | sed 's/.\///' | while read k; do
        find ../emotions/ -iname "*$k*" | sed 's/..\/emotions\///' | sed 's/.txt/.mp3/' | while read j; do
            m=`echo $n | sed 's/.\///'`
            echo "Renaming" $m "to" $j
            cp "$m" "$j"
Instead of using "while read" to snatch the output of the multi-piped sed command (I don't know what to call it), is it possible to assign the output of the last sed command to a variable?

j=`echo $n | sed 's/.wav././' | sed 's/[0-9]*\ //' | sed 's/-//' | sed 's/\ -\ /*/' | sed 's/.mp3//' | sed 's/.\///'`
does not work..

I would also like the user to be able to confirm the renaming of each individual file (e.g. y/n keyboard input). I tried to use read for this, but for some reason nothing happens.
Old 10-28-2009, 11:33 PM   #4
Registered: Feb 2009
Posts: 347

Rep: Reputation: 72
I am not sure if this is what you want, but to assign the results of commands to variable you can use the following syntax


i.e. in your case

j=$(`echo $n | sed 's/.wav././' | sed 's/[0-9]*\ //' | sed 's/-//' | sed 's/\ -\ /*/' | sed 's/.mp3//' | sed 's/.\///'`)
Old 10-29-2009, 12:57 AM   #5
LQ Guru
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,733

Rep: Reputation: 671Reputation: 671Reputation: 671Reputation: 671Reputation: 671Reputation: 671
The main change I would recommend is to first prepare a file containing a list of the lyrics files. Running a directory list or find command on such a large number of files will take time. You don't want that inside a loop. Preparing a directory listing to work with before your loop will save a lot of time.

One thing you can do is use a single sed command instead of all of the pipe commands.
sed 'command1;command2;command3;command4'
sed -e 'command1' -e 'command2' -e 'command3' -e 'command4'

You can also create a file containing your sed commands and call the sed command like: "sed -f replacemp3s.sed". That would allow you to debug the sed commands as a separate entity.

If you do use sed to process the list of mp3 music files, you could use the memory registers to enable print the parts that match in the repacement string. This is commonly used to cut out parts of a line which you want to do.

Maybe this example will give you some ideas:
echo '01 - Dungen - Panda.mp3' | 
sed -n 's/^[[:digit:]][[:digit:]]* - \(.*\) - \(.*\).mp3/\1\t\2/p' | 
while read name artist; do 
   echo name=$name,artist=$artist; 
name=Dungen artist=Panda
or this one:
eval $(echo '01 - Dungen - Panda.mp3' | 
       sed -n 's/^[[:digit:]][[:digit:]]* - \(.*\) - \(.*\).mp3/name="\1" artist="\2\"/p')
~> echo $name
~> echo $artist
For other ideas, look at the `-f' option for grep. You could construct regular expression strings from the list of mp3 files and use that in a search of a list of the lyric files. Or you could use variables in a grep or sed command to locate the matching lyrics file from the list.

The '-n' option I used in the sed example suppresses the output. The later `p' command after the replacement prints the line only if there was a match. This can eliminate problems if a filename doesn't match the pattern. I would recommend that you move the file to another directory after renaming it, since the pattern before and after are similar. Also using a text file of the mp3 directory for debugging until you get the script correct. You could print out the mv command line to create a script of mv commands. This would allow you to visually inspect it for problems before actually executing it.

At work I need to perform something similar, locating files with leading zero's and removing them from the filenames. There are thousands of files. I can access the directory from my workstation, but don't have permission to rename them. So I construct a windows batch file (using sed in a cygwin script), redirect the output to a batch file on the server, and then log in to the server and run the script.

Good Luck!

Last edited by jschiwal; 10-29-2009 at 01:03 AM.
Old 11-01-2009, 02:17 AM   #6
LQ Newbie
Registered: Oct 2009
Posts: 3

Original Poster
Rep: Reputation: 0
Thanks for the replies, I learned a lot from that .


Thread Tools Search this Thread
Search this Thread:

Advanced Search

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
pipe as Bash function input eldorel Programming 4 03-05-2009 10:38 AM
Bash script and chroot with a pipe Luminoth Programming 6 09-19-2007 01:01 PM
Read the output from a pipe with bash ? fluppi Linux - Software 3 01-13-2004 12:59 PM

All times are GMT -5. The time now is 06:10 AM.

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