You are not logged in.

#1 2011-12-23 17:21:28

skottish
Forum Fellow
From: Here
Registered: 2006-06-16
Posts: 7,942

Question on bash parameter passing [SOLVED]

My mother wanted to convert some of her m4a files to mp3 files to be compatible with a new player that she bought. So, she when through and manually changed the m4a extension to mp3 smile Of course this broke things like Banshee that rely on both file extensions and tags. I decided to write a script to fix it:

#!/bin/bash

find ./ -name '*.mp3' > mp3list

grep -v '^#' $1 |
while read f
do
   TEMP=$( file -b "$f" | awk '{print $3 $4}')
   if [ "$TEMP" == "MPEGv4" ]
   then 
      echo "$f is fixed"
      rename .mp3 .m4a "$f"
   fi
done

rm ./mp3list

When I originally wrote the script, the file 'mp3list' already existed. As I was doing the final touches, I added the code to remove it. I went to test the script a couple more times and I didn't think to add the file back. My question is, how does bash know to use 'mp3list' as a parameter when it doesn't exist before the script is run?

Last edited by skottish (2011-12-23 21:06:20)

Offline

#2 2011-12-23 17:54:08

Awebb
Member
Registered: 2010-05-06
Posts: 6,688

Re: Question on bash parameter passing [SOLVED]

I'm not sure I understand your question.

You create mp3list in line 4 and delete it in the end. What's your $1 parameter for?

Sorry, I might evade your question a little, but how about this:

#!/bin/bash
checknrename() {
    if [[ `file -b $1 | grep MPEGv4` ]]; then
        rename .mp3 .m4a "$1"
        printf "$1 has been fixed"
    else
        printf "$1: nothing to fix"
    fi
}

find ./ -name '*.mp3' -exec checknrename {} \;

This way you don't need to worry about your file list.

Last edited by Awebb (2011-12-23 17:55:03)

Offline

#3 2011-12-23 17:57:59

ga01f4733
Member
From: NYC
Registered: 2008-12-05
Posts: 117

Re: Question on bash parameter passing [SOLVED]

Hi,
well you're  generating a mp3list file in line 4. 
Actually, I dont have a mp3list file , if I run your script, it creates one in the present directory containing all the mp3 files it had found.

hope this helps

cheers

Last edited by ga01f4733 (2011-12-23 17:59:39)


There are no foreign lands. It is the traveler only who is foreign. --R.L Stevenson

Offline

#4 2011-12-23 18:01:17

skottish
Forum Fellow
From: Here
Registered: 2006-06-16
Posts: 7,942

Re: Question on bash parameter passing [SOLVED]

Whoops, the script is started with './fixext mp3list'. And now I understand why it worked. The find line created the file that grep was looking for and wasn't implicitly understood by bash.

But, who cares? Awebb, your solution is a million times better than mine. I don't write much bash, so I was hacking my way through the solution bit by bit. I knew that there would be a better way, but I wanted to get a working copy on my own in order to understand better. Thanks to you Awebb, I'm even less of a bashtard!

@ga01f4733,

Thanks. I was writing as the same time as you and of course you are correct.

Last edited by skottish (2011-12-23 18:03:47)

Offline

#5 2011-12-23 18:06:01

Awebb
Member
Registered: 2010-05-06
Posts: 6,688

Re: Question on bash parameter passing [SOLVED]

skottish wrote:

But, who cares? Awebb, your solution is a million times better than mine. I don't write much bash, so I was hacking my way through the solution bit by bit. I knew that there would be a better way, but I wanted to get a working copy on my own in order to understand better. Thanks to you Awebb, I'm even less of a bashtard!

Is that a friendly "thank you" or a friendly "gtfo"? :-D

Offline

#6 2011-12-23 18:10:51

skottish
Forum Fellow
From: Here
Registered: 2006-06-16
Posts: 7,942

Re: Question on bash parameter passing [SOLVED]

Awebb wrote:
skottish wrote:

But, who cares? Awebb, your solution is a million times better than mine. I don't write much bash, so I was hacking my way through the solution bit by bit. I knew that there would be a better way, but I wanted to get a working copy on my own in order to understand better. Thanks to you Awebb, I'm even less of a bashtard!

Is that a friendly "thank you" or a friendly "gtfo"? :-D

It's a major thank you. Your script doesn't work yet for me, but it gives me an idea of how to eliminate some of the unnecessary stuff and it will help me learn to use functions within bash scripts.

--EDIT--

I couldn't get it to work because find couldn't locate the function. So I -exec bash -c 'blah blah' and it runs. Now I'm back to find struggling with spaces in file names, which was a problem that I had originally; That is why I was using the file list in the first place. Any ideas? It's not important as my code works, but I would like to understand it all the same.

By the way, I eliminated awk with an idea from Awebb's post, so things are getting leaner.

Last edited by skottish (2011-12-23 18:51:18)

Offline

#7 2011-12-23 19:01:38

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,330
Website

Re: Question on bash parameter passing [SOLVED]

RE: spaces in file names.

The best solution is to never put spaces in file names.  A more practical solution for the real world is simply to enclose any reference to a variable in double-quotes so $1 becomes "$1".  Of course if it's already within an enclosing quite you'd need to escape the quotes (\"$1\").

The only edit to Awebb's script would be in the third line, note added quotes

    if [[ `file -b "$1" | grep MPEGv4` ]]; then

Every reference to $1 should be quoted, but as-is, every other reference to it is already quoted.


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Online

#8 2011-12-23 19:17:50

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,330
Website

Re: Question on bash parameter passing [SOLVED]

What I mean by the "real world" is a digital world in which users of another OS tend to put spaces in nearly every file name and they send such abominations about via email.

I get a bit angry each time I receive one of these.  I get a bit angry, but I don't get worried, because I make sure that everything I use is set up to properly handle such annoyances.

As an aside, a particular piece of proprietary research equipment I work with and have to analyze data files from puts a 'bang' (!) at the beginning of every file NAME, several spaces in the middle, and a serialized number in the extension.  This has provided me with many nights of dreaming how to properly punish them for their crimes.  I think I invented a couple new cuss words when I was first handed a disk *full* of files with names like

!Some Test of something - 12h38m05s - record 1.ST134
!Some Test of something - 12h38m07s - record 2.ST149

Such things make you appreciate the importance of how to use bash variables and regular expressions properly.


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Online

#9 2011-12-23 19:29:27

skottish
Forum Fellow
From: Here
Registered: 2006-06-16
Posts: 7,942

Re: Question on bash parameter passing [SOLVED]

Thanks Trilby.

This is the closest thing to something functional from the posts above as I understand them right now with some improvements and corrections of my own:

#!/bin/bash

checknrename() {
    if [[ `file "$1" | grep "MPEG v4"` ]]; then
        rename .mp3 .m4a "$1"
        printf "$1 has been fixed\n"
    else
        printf "$1: nothing to fix\n"
    fi
}

export -f checknrename

find ./ -name '*.mp3' -exec bash -c 'checknrename {}' \;

It still can't handle spaces in file names and coughs up a bunch of errors on special characters because of it.

Last edited by skottish (2011-12-23 19:30:00)

Offline

#10 2011-12-23 19:42:19

Awebb
Member
Registered: 2010-05-06
Posts: 6,688

Re: Question on bash parameter passing [SOLVED]

Oww, that find command lives in a world of it's own o.O. But there must be a way. Completely new to me. So after a little research:

#!/bin/bash

checknrename() {
    if [[ `file -b "$1" | grep MPEGv4` ]]; then
        rename .mp3 .m4a "$1"
        printf "$1 has been fixed\n"
    else
        printf "$1: nothing to fix\n"
    fi
}

export -f checknrename

find ./ -name '*.mp3' -exec bash -c 'checknrename "{}"' \;

I find this amazing. I have to write bash scripts every day at work, but every time I approach a new problem, I learn something new.

Offline

#11 2011-12-23 19:44:34

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,330
Website

Re: Question on bash parameter passing [SOLVED]

<facepalm>

Yes, I suspect the errors are from the final find line.  The files with spaces are being passed to the function as separate parameters to start with.  To make sure, could you share those errors that are being 'coughed up'?

Here's a different approach.  I can't say better, but it is what I'm more familiar with so I can comment more:

#!/bin/bash

for f in "$(find . -name '*.mp3')"; do
    [[ `file "$f" | grep "MPEG v4"` ]] && rename .mp3 .m4a "$f"
done

I've left out the notifications, but this can be added back.  The functional difference is the loop through the results of 'find' rather than passing them through the function.

Last edited by Trilby (2011-12-23 19:45:25)


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Online

#12 2011-12-23 20:19:07

falconindy
Developer
From: New York, USA
Registered: 2009-10-22
Posts: 4,111
Website

Re: Question on bash parameter passing [SOLVED]

This can be done more cleanly... particularly, looping over the output of find in a for loop assures you that you will break on whitespace. Leverage find.

find . -type f -name '*.mp3' -exec bash -c 'for arg; do file "$arg" | grep -q "MPEG v4" && rename .mp3 .m4a "$arg"; done' _ {} +

This passes all results from find to a bash shell which then loops over the results and acts accordingly. The _ voodoo at the end is a dummy parameter to bash. It takes the place of $0 (the name of the program).

Offline

#13 2011-12-23 21:09:45

skottish
Forum Fellow
From: Here
Registered: 2006-06-16
Posts: 7,942

Re: Question on bash parameter passing [SOLVED]

falconindy wrote:

This can be done more cleanly... particularly, looping over the output of find in a for loop assures you that you will break on whitespace. Leverage find.

find . -type f -name '*.mp3' -exec bash -c 'for arg; do file "$arg" | grep -q "MPEG v4" && rename .mp3 .m4a "$arg"; done' _ {} +

This passes all results from find to a bash shell which then loops over the results and acts accordingly. The _ voodoo at the end is a dummy parameter to bash. It takes the place of $0 (the name of the program).

That's freakin' slick falconindy! Very, very cool.

It's funny how this same problem has gone unsolved in many forum posts all over the spectrum. Now they have a place to go.

--EDIT--

I'm slightly less of a bashtard now, but apparently I'm not as thoughful as usual...

Thank you to everyone that posted here. All of you had great ideas and it helped me understand quite a bit more. I appreciate it.

Last edited by skottish (2011-12-24 03:32:59)

Offline

Board footer

Powered by FluxBB