How can I process the results of find in a bash script?

BashFind

Bash Problem Overview


I'm trying to use an array to store a list of file names using the find command.

For some reason the array fails to work in the bash used by the school, my program works on my own laptop though.

So I was wondering if there's another way to do it, this is what i have:

array = (`find . -name "*.txt"`)  #this will store all the .txt files into the array

Then I can access the array items and make a copies of all the files using the cat command.

Is there another way to do it without using an array?

Bash Solutions


Solution 1 - Bash

You could use something like this:

find . -name '*.txt' | while read line; do
    echo "Processing file '$line'"
done

For example, to make a copy:

find . -name '*.txt' | while read line; do
    echo "Copying '$line' to /tmp"
    cp -- "$line" /tmp
done

Solution 2 - Bash

I was having issue with Johannes Weiß's solution, if I was just doing an echo it would work for the full list of files. However, if I tried running ffmpeg on the next line the script would only process the first file it encountered. I assumed some IFS funny business due to the pipe but I couldn't figure it out and ran with a for loop instead:

for i in $(find . -name '*.mov' ); 
do
    echo "$i"
done

Solution 3 - Bash

I think starpause has the cleanest solution, however it fails when there is whitespaces in paths. This is fixed by setting IFS. The correct answer is therefore:

IFS=$'\n'
for i in $(find . -name '*.mov' ); 
do
    echo "$i"
done
unset IFS

You unset IFS in order to reset behaviour for IFS and as to why the $ is needed in IFS=$'\n', see https://unix.stackexchange.com/questions/184863/what-is-the-meaning-of-ifs-n-in-bash-scripting

Solution 4 - Bash

Just don't put blanks around the equals sign:

ar=($(find . -name "*.txt"))

Avoid backticks, if possible, since they're deprecated. They can be easily confused with apostroph, especially in poor fonts, and they don't nest so well.

In most cases you will be best served if you iterate through a find-result directly with -exec, -execdir, -ok or -okdir.

For and while loops are hard to do right when it comes to blanks in filenames or newlines and tabs.

find ./ -name "*.txt" -exec grep {} ";"

The {} doesn't need masking. You will often see a combination find/xargs which starts an additional process too:

find ./ -name "*.txt" | xargs grep {} ";"

Solution 5 - Bash

find . -name '*.txt' | while IFS= read -r FILE; do
    echo "Copying $FILE.."
    cp "$FILE" /destination
done

Solution 6 - Bash

One more variant to change some variable inside while loop which uses subshell

concat=""

while read someVariable
do
    echo "someVariable: '$someVariable'"
    concat="$concat someVariable")
done < <(find "/Users/alex" -name "*.txt")

echo "concat: '$concat'"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShellscriptbeginnerView Question on Stackoverflow
Solution 1 - BashJohannes WeissView Answer on Stackoverflow
Solution 2 - BashstarpauseView Answer on Stackoverflow
Solution 3 - BashberuicView Answer on Stackoverflow
Solution 4 - Bashuser unknownView Answer on Stackoverflow
Solution 5 - Bashghostdog74View Answer on Stackoverflow
Solution 6 - BashyoAlex5View Answer on Stackoverflow