Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm trying to write a script to unify two separate commands I run by hand into a single bash script I can then cron.

The first command is a simple find on files with a certain name and size

find /some/path -type f -name file.pl -size +10M

This will produce several matching files and their full path. I then copy these paths by hand into a for loop as arguments to the next script.

for path in /some/path/1/file.pl /some/path/2/file.pl /some/path/3/file.pl ; do perl /my/script.pl $path ; done

Seems like it should be easy to get this into a single shell script but finding it a struggle.

share|improve this question
2  
Note $(command) and `command` are equivalent, but I think $(command) is more readable. –  richard Aug 14 '14 at 11:23

3 Answers 3

up vote 5 down vote accepted

That's what the -exec predicate is for:

find /some/path -type f -name file.pl -size +10M -exec perl /my/script.pl {} \;

If you do want to have your shell run the commands based on the output of find, then that will have to be bash/zsh specific if you want to be reliable as in:

  • zsh:

    IFS=$'\0'
    for f ($(find /some/path -type f -name file.pl -size +10M -print0)) {
      /my/script.pl $f
    }
    

    though in zsh, you can simply do:

    for f (./**/file.pl(.LM+10)) /my/script.pl $f
    
  • bash/zsh

    while IFS= read -rd '' -u3 file; do
      /my/script.pl "$file"
    done 3< <(find /some/path -type f -name file.pl -size +10M -print0)
    

Whatever you do, in bash or other POSIX shells, avoid:

for file in $(find...)

Or at least make it less bad by fixing the field separator to newline and disable globbing:

IFS='
'; set -f; for file in $(find...)

(which will still fail for file paths that contain newline characters).

share|improve this answer
    
@Gnouc, no quotes are not needed here in zsh (unless in sh or ksh emulation). There's no shell that I know where {} needs quoted either. –  Stéphane Chazelas Aug 14 '14 at 12:11
    
I am guessing in the bash/ zsh while loop you mean to pass $file to script.pl? –  1_CR Aug 14 '14 at 12:43
    
@1_CR, thanks. Fixed now. –  Stéphane Chazelas Aug 14 '14 at 12:59

If you are using the GNU tools, the following should also work:

find /some/path -type f -name file.pl -size +10M -print0 | xargs -0 -n 1 -r perl /my/script.pl

Explanation:

  • The option -print0 causes GNU find to separate the file names with \0 bytes. Since \0 bytes cannot be part of the file name, this uniquely separates the file names.
  • The option -0 tells GNU xargs to read standard input as \0-separated list of file names.
  • The option -n 1 enforces that no more than one file name is passed to your script (if your script can handle a complete list of files as argument, just omit that).
  • Finally, -r is another GNU extension which prevents your program from being run if no file names are supplied.
share|improve this answer
    
That has the side effect of affecting perl's stdin. I can't see any good reason of preferring that over the standard -exec ... variant. –  Stéphane Chazelas Aug 15 '14 at 14:32
    
@StéphaneChazelas: For this specific case, it probably has no advantage. But in a more general case, you might want to modify the list of file names before passing it to the commands. With the pipe form, you can do that by inserting an additional command in the pipeline. For example, if for some reason you want to process the files in sorted order, you can just put a sort -z in the pipeline between find and xargs. Or select a subset using regexps by inserting a grep -z. –  celtschk Aug 15 '14 at 16:06

This should do it

for path in `find /some/path -type f -name file.pl -size +10M`; do perl /my/script.pl $path ;done
share|improve this answer

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.