Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Why doesn't

find . -type f -exec echo $(file={}; echo ${file:0:5}) \;

give the first five characters of the file, while this works:

find . -type f -exec bash -c 'echo ${1:0:5}' funcname {} \;

Background:

I'm trying to batch convert a tree full of images to thumbnails, and I want to rename them on the fly by adding '_thumb' at the end of the filename but before the extension. This renaming process is easy for one file:

file='I am a picture.jpg'
mv \"$file\" \"${file%\.*}_thumb.${file##*\.}\"

(the second line expands to mv "I am a picture.jpg" "I am a picture_thumb.jpg")

but when I try to encapsulate this command in the -exec parameter of find(1) I cannot manipulate the filename given by find (examples simplified):

find . -type f -exec ${{}:0:5}) \;

gives

bash: ${{}:0:5}: bad substitution

Using a subshell I get a bit further:

find . -type f -exec echo $(file={}; echo ${file:0:5}) \;

this does echo the filename, but does not execute the string manipulation for some reason.

I finally found the solution in this SO post:

find . -type f -exec bash -c 'echo ${1:0:5}' funcname {} \;

but I don't understand why this would work when the $(...) construct does not.

share|improve this question

1 Answer 1

up vote 5 down vote accepted

exec does what it says: uses exec(). It doesn't involve a shell unless it's told to (-exec bash ...), and if it did you would still need single quotes to keep your interactive shell from interpreting the variable interpolations. (The shell is not magic and does not know that you intended those to be interpolated by something else.)


For example, when you use the following command:

find . -type f -exec echo $(file={}; echo ${file:0:5}) \;

your shell first performs process substitution by executing $(file={}; echo ${file:0:5}), which simply outputs {}, then executes the final command:

find . -type f -exec echo {} \;
share|improve this answer
    
Ah, I see now. Of course ${file:0:5} returns {} if $file={}. When I use $(file={}; echo ${file:0:1}) it indeed outputs only {. –  Tim Apr 9 '12 at 16:04

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.