Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I have the following script - its supposed to loop files names using find but it seams to break the files names up by a space? I need the file names to remain intact

#!/bin/bash

for file in `find -name "*.avi"`
do
./myscript $file
done

Can anyone help me?

Thanks

share|improve this question
    
possible duplicate of Linux command to remove directories with white spaces –  womble Jul 8 '12 at 15:37
    
I updated the question to be more accurate of what I want to do –  Rob Jul 8 '12 at 15:43
1  

4 Answers 4

up vote 4 down vote accepted
find -name "*.avi" -print0 | xargs -0 -n 1 echo

You don't have to echo in xargs:

find -name "*.avi" -print0 | xargs -0 -n 1 ./myscript
share|improve this answer
    
This is another way to output the filename - I need to loop file names to another script (in the example above I replaced the command with echo) –  Rob Jul 8 '12 at 15:38
    
So show us what you actually want to do then. We can't help you do what you want to do if you don't tell us what you want to do. –  womble Jul 8 '12 at 15:38
    
+1 brilliant ! thanks –  Rob Jul 8 '12 at 15:45

Also: find -name "*.avi" -exec ./myscript '{}' \;

Womble's answer definitely works in the majority of cases, but Xargs isn't perfect with spaces across all implementations. I've never found find's 'exec' mode to break. Solaris was particularly cranky in that respect.

Obviously, the '-print' would be better for simply generating output for a list of files in a for loop. But if you're running a command on a list of files, it's more efficient to just run the '-exec' option.

share|improve this answer

If you don't need recursion:

#!/bin/bash

for file in *.avi
do
    ./myscript "$file"
done

Note that the quotes around the variable are essential.

Edit:

As kojiro points out, if you need recursion and you have Bash 4, you can add shopt -s globstar and change the glob to **/*.avi.

share|improve this answer
    
If a file name has spaces, this method will break. If it has \n or other strange characters, it is also a security risk. Think of "/tmp/file\n/etc/shadow" –  hayalci Jul 8 '12 at 19:54
1  
@hayalci: No, you are completely wrong. It works perfectly with such filenames and without any security risks. Globbing with a for loop is the correct way to do this when recursion is not needed. –  Dennis Williamson Jul 8 '12 at 20:24
    
If he does need recursion and has bash 4, he can just use shopt -s globstar; for file in **/*.avi –  kojiro Jul 8 '12 at 22:13
    
@kojiro: Thanks, I should have mentioned that and I will add it to my answer. –  Dennis Williamson Jul 8 '12 at 22:15
    
@DennisWilliamson: You are right, I confused the issue with "for i in `ls *.avi`" case –  hayalci Jul 13 '12 at 13:33

In addition to the solutions based on xargs and the find -exec there is also the option of piping to while read. It has the benefit of allowing you to structure your script in a more classic loop manner. Let me apply it to your example.

find -name "*.avi" | while read avifile; do
  ./myscript "$avifile"
done
share|improve this answer
2  
By default read will support escaping, so you need -r. And your solution will break with filenames containing newlines. –  Pierre Carrier Jul 8 '12 at 16:03
    
@Pierre: I have so far never encounted a regular space situation where I have needed the -r parameter (to read?), but thanks for the pointer, I'll look into it. Agree that this solution would break on newline. Assumed the original questioner only dealt with the regular space character. When expecting arbitrary whitespace, or any other really crazy characters I agree on xargs -0 being the better choice. Well, either that or doing something more robust in a language such as Perl, Python, etc. –  andol Jul 8 '12 at 16:12
    
-r is not needed for spaces, but in case a backslash appears in the filename. –  Pierre Carrier Jul 8 '12 at 16:16
    
Ah, now I follow, thanks. –  andol Jul 8 '12 at 16:17

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.