In a bash script I’m trying to use the content of a variable to be used as options for the find command:
#!/bin/bash FILE_EXTENSIONS=( txt png jpg ) FIRST=1 for FILE_EXTENSION in ${FILE_EXTENSIONS[@]} do # echo "$FILE_EXTENSION" if [[ $FIRST == 1 ]] then FIND_FILTER="-iname '*.$FILE_EXTENSION'" FIRST=0 else FIND_FILTER="${FIND_FILTER} -o -iname '*.$FILE_EXTENSION'" fi done # Read and write only for user and group, ignore case '-iname' #find . -type f "$FIND_FILTER" -exec chmod 660 {} ; echo Find filter: $FIND_FILTER # This might work with some already provided suggestions: find . -type f $FIND_FILTER # But this fails so far find . -type f $FIND_FILTER -exec chmod 660 {} ; #EOF
The aim is to set proper access rights as for what ever reason quite some files (such as pictures or office documents) are marked executable.
So in reality the script above has several arrays with file extensions concatenated, but the script shows the problem.
The first approach would have been to iterate over the final array and call find each time. But from a runtime point of view it would be stupid to search each time over and over again.
I also could simply do this in python but for once I thought I would like to solve it with linux basic means in bash.
It looks like the content of the FIND_FILTER variable is correct (at least what is printed with echo) but then … it doesn’t work.
Any suggestions what is going wrong?
Advertisement
Answer
You started using arrays (nearly) correctly, but then abandoned them for a space-separated string. Keep using arrays.
- Always quote the expansion of an
@
-indexed array; otherwise, there is no reason to use@
over*
. - As a general rule, avoid all-caps variables names; they are (mostly) reserved for use by the shell.
- Enclose the filters joined by
-o
in escaped parentheses so thatfind
treats them as a single condition to be met in addition to the-type
primary. - Use
-exec ... +
so thatchmod
can operate on multiple files per call, rather than calling it once for each file separately.
#!/bin/bash file_extensions=( txt png jpg ) first=1 for ext in "${file_extensions[@]}" do # echo "$ext" if [[ $first == 1 ]] then find_filter=(-iname "*.$ext") first=0 else find_filter+=( -o -iname "*.$ext") fi done # Read and write only for user and group, ignore case '-iname' find . -type f ( "${find_filter[@]}" ) -exec chmod 660 +