Using basename in a command run with find -exec

About writing shell scripts and making the most of your shell
Forum rules
Topics in this forum are automatically closed 6 months after creation.
Locked
BreadTed

Using basename in a command run with find -exec

Post by BreadTed »

What I want to do is convert a whole collection of wav files to mp3 files.

I am trying to follow an answer given in https://stackoverflow.com/questions/216 ... -in-a-loop , namely,

find ./ -name "*.wav" -exec ffmpeg -i "{}" -ab 320k -ac 2 '$(basename {} wav)'.mp3 \;

and the basename business is giving me a right headache. It is clearly not working properly as I get (e.g. for the song "07 Brakes On.wav") the error:

$(basename ./07 Brakes On.wav wav).mp3: No such file or directory

So the basename is not executing but am at a loss as to how it can be fixed. Doing it in a loop seems to have its own problems.

Alternative suggestions for batch mp3 conversions also welcome, I just want to get it done!
Last edited by LockBot on Wed Dec 28, 2022 7:16 am, edited 1 time in total.
Reason: Topic automatically closed 6 months after creation. New replies are no longer allowed.
BreadTed

Re: Using basename in a command run with find -exec

Post by BreadTed »

I should add, I'm using Mint 18.2, and the music files are on a mounted network drive.

But I think the main problem is that I cannot get my head around the proper use of dollar signs, single and double quotes, brackets, etc etc.
User avatar
xenopeek
Level 25
Level 25
Posts: 29507
Joined: Wed Jul 06, 2011 3:58 am

Re: Using basename in a command run with find -exec

Post by xenopeek »

Two minor problems with your command:
- the filename argument to basename should be quoted, as it may contain spaces
- and I think the suffix argument to basename should start with a dot (this may possibly work, but that is what basename examples do)

The major problem is the substitute command $(..) only works when running a shell. You're running find, which doesn't know about shell substitute commands :) So if you want to use that as argument for find's exec you need to do that by having find execute a shell that executes your command.

Putting it all together it would be something like:
find . -name \*.wav -exec bash -c 'ffmpeg -i "{}" -ab 320k -ac 2 "$(basename "{}" .wav).mp3"' \;
Image
gm10

Re: Using basename in a command run with find -exec

Post by gm10 »

Is the basename really intended though, i.e. do you want to drop the subfolders? Just going by the example name you provided I'm thinking you'd end up with quite a mess doing it that way.
rene
Level 20
Level 20
Posts: 12240
Joined: Sun Mar 27, 2016 6:58 pm

Re: Using basename in a command run with find -exec

Post by rene »

The good point one up can be worked around with use of -execdir rather than -exec but alternatively...

find -exec syntax is a bit of a disaster even for experienced command line users: a trick I oft use and generally suggest is launching /bin/bash with the filename as a parameter:

Code: Select all

find ... -exec /bin/bash -c '...' -- \{} \;
This provides you with full bash possibilities for the bit between single quotes, which receives the filename as its "$1". I.e., in your case you could use

Code: Select all

find -name "*.wav" -exec /bin/bash -c 'ffmpeg -i "$1" -ab 320k -ac 2 "${1%%.wav}.mp3"' -- \{} \;
This also takes the opportunity to use the bash parameter expansion ${parameter%%word} syntax to replace ".wav" with ".mp3" (see the bash manpage) rather than basename but that bit's not primary. Exec'ing /bin/bash with the filename as parameter is: it provides for significantly better syntax/control.
BreadTed

Re: Using basename in a command run with find -exec

Post by BreadTed »

Thanks for the replies. I took xenopeek's answer (it was the only one there at the time!), using execdir instead of exec after noticing the problem on a set of test files (pats self on back).

It didn't like a couple of files which had backticks in the title but I just did those manually. Although it did take me a while to cd into a folder which also had a backtick in its name...

And while I was waiting for the converting to finish, I even wrote a little script to work out the progress :D
Locked

Return to “Scripts & Bash”