LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (http://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Script question with find -exec (http://www.linuxquestions.org/questions/linux-newbie-8/script-question-with-find-exec-880518/)

linuxbird 05-13-2011 08:04 AM

Script question with find -exec
 
I am trying to check flac files in a multi-level directory structure, and would ideally like to get ordered output with the full path file name.

I could write a multiline script, but was wondering if there were better ways of accomplishing this.

The current command I am using is:

Code:

find . -name '*flac' -exec flac -t {} \;

szboardstretcher 05-13-2011 08:23 AM

"ordered output with the full path file name"

What does that mean? Where do you want this output from? Could you provide an example of what you are getting, and what you would like?

David the H. 05-13-2011 08:43 AM

What do you mean exactly by "ordered output"? What do you mean by "full path file name" (those terms don't quite go together). Give us an actual example of what kind of results you want, and we'll try to help you.

As a first step though, find by default outputs file names appended with the input search path you feed it. So if you use "find ." you'll get output formatted as "./file". If you use "find /full/path/to" then your output will be "/full/path/to/file".

Also, instead of running the command directly, you could create a separate script that does the actual processing, including formatting the filenames, and call that with -exec.

PTrenholme 05-13-2011 09:05 AM

You could try something like this:
Code:

$!/bin/bash
find . -name '*flac' -exec flac -t '{}' ';' | while readline path;do base=$(basename ${path});sorted[${basename}]="${path}";done;for p in "$path[@]";do echo "${path[${p}]};done

Note: Untested code - I'm on an old XP system right now, defraging a large disk for my sister.

linuxbird 05-13-2011 12:25 PM

Thanks everyone. Ideally I would like something like:


./file/path/track.flac <then the flac -t option output>

I'm not real picky, I would just like to do hundreds of files, and then scan through the list for defects.

In terms of order, I guess I would like to do something akin to a:

find . | grep '.flac' | sort | exec {something}

But I am not sure that I really understand the use of exec outside the find command.

And for getting the file name printed I was thinking I could use a tee command after the sort, before the exec.

So I'm kind fishing for guidance and ideas. Thanks everyone!

David the H. 05-13-2011 07:08 PM

"-exec" is just what it says on the tin. Execute the specified command for each matching file, with "{}" being where the file name goes.

However it's really only designed for simple, one-shot style operations. If you have a series of complex commands to run then it's usually better to write up a shell script of some kind, and only use find to produce the list of files for it to operate on.

Edit: There other exec commands out there, such as the bash built-in command, but those are completely different beasts. Don't confuse them with the find option.

AnanthaP 05-13-2011 10:40 PM

find . -name "*flac" -print | sort
should sort by directory path.

find . -name "*flac" -print | awk '{print $NF, $0}' | sort
should sort by file name first.

OK

David the H. 05-14-2011 01:23 PM

Code:

find . -name "*flac" -print | awk '{print $NF, $0}' | sort
But this has a side effect of awk printing the filename twice, which wouldn't be good if you're trying to pipe the output into further commands. Also, I think you forgot to change the field separator to "/".


One common way to process sorted input is to use xargs to execute the commands, instead of -exec.
Code:

find . -name "*flac" -print0 | sort -hz | xargs -0 flac -t
The -print0 option in find separates the output by null characters instead of newlines, which makes it possible to easily handle files with spaces or other reserved characters, and sort's -z and xargs -0 options tell them to process the null-terminated input. Whether you need this or not depends on what kind of filenames you have.

Finally, I added the -h human-numeric-sort option to sort, so that 10 will come after 9 instead of after 1.

As for the full-path-in-the-output thing, I see now that the problem is actually with flac. It only displays the filename when printing the results of -t. There appears to be nothing we can do with find or anything else that can affect that.

The only thing I can think of then is to set up a script to check the test results.
Code:

#!/bin/bash

while read file ; do

    flac --totally-silent -t "$file"

    if (( $? == 0 )); then
          echo "valid: $file"
    else
          echo "not valid: $file"
    fi

done  < <( find "$1" -name "*.flac" -print | sort -h )

exit 0

Launch it as "scriptname startdir".

So basically I've turned off flac's default output and instead print valid or invalid depending on the exit code of the test. According to the man page, the exit code will be 0 if the file is valid, and 1 if not. I'm assuming here that you won't need to worry so much about the full path if you can easily spot the bad files in the output, but if you still want to see it, just make sure the starting input contains the full path to the input.

AnanthaP 05-14-2011 11:31 PM

Quote:

Code:
find . -name "*flac" -print | awk '{print $NF, $0}' | sort
But this has a side effect of awk printing the filename twice, which wouldn't be good if you're trying to pipe the output into further commands. Also, I think you forgot to change the field separator to "/".
Actually, putting $NF first means that I need not worry about the field separator.

But what I wanted to discuss was single-quotes (in the OP's use of '*flac' .v. "*flac" .

OK

Tinkster 05-15-2011 12:34 AM

Quote:

Originally Posted by AnanthaP (Post 4356634)
Actually, putting $NF first means that I need not worry about the field separator.

But what I wanted to discuss was single-quotes (in the OP's use of '*flac' .v. "*flac" .

OK



Ummm ... no. Unless he has lots of filenames with spaces/tabs in them all you
get is the same file printed twice on the same line, because then $NF==1. And
w/ only one field $1 and $0 are the same thing. Now I'm not suggesting that
printing $NF for files w/ spaces should be considered meaningful for sorting... ;D



Cheers,
Tink

catkin 05-15-2011 12:36 AM

David the H's suggestion could be coded as
Code:

#!/bin/bash

while read file ; do

    flac --totally-silent -t "$file" && echo "valid: $file" || echo "not valid: $file"

done  < <( find "$1" -name "*.flac" -print | sort -h )

exit 0


David the H. 05-15-2011 03:04 AM

Yes, it can be done that way, but I like to avoid the x && y || z pattern most of the time. I prefer the clarity to the conciseness.

There's also a potential pitfall you can avoid by not depending too much on that pattern:
http://mywiki.wooledge.org/BashPitfa...d2_.7C.7C_cmd3

David the H. 05-15-2011 03:21 AM

@AnanthaP, if you want to sort by filename, you have to separate the name from the path. As Tinkster pointed out, if awk's field separator is the default, then each file path will be seen as a single word and the output will be "/path/to/filename /path/to/filename", which is pretty much meaningless.

Of course even if you do change the FS to"/", all you get is an output that looks like "/path/to/filename filename", which is equally useless further down the line.

Try it yourself if you don't believe me. I did. ;)

But this makes me wonder, is it possible to tell sort to sort on the last field of the line, whatever the length? I don't think so, but I could be wrong.


All times are GMT -5. The time now is 09:23 PM.