0

I need to use the find command to get files that are not declared in an array.

# ALLOWED extensions
ext_allowed=("*.cs" "*.csproj" "*.sln" "*.json")

combined=""
for ext in "${ext_allowed[@]}"; do
        combined="$combined -not -name \"$ext\""
done

# This doesn't work :(
find $location $combined -not -type d

# This does work, but it looks the same??
find $location -not -name "*.cs" -not -name "*.csproj" -not -name "*.json" -not -name "*.sln" -not -type d

The variable location, just holds the location of the files. I also tried it already with the -o option in between, but this also does not work.

Can anyone help me out please? Thanks

Alex
  • 25
  • 2
  • Construct `combined` as an array instead of a string variable - see for example [Is there a way to expand a variable into multiple arguments without globbing in bash?](https://unix.stackexchange.com/questions/638242/is-there-a-way-to-expand-a-variable-into-multiple-arguments-without-globbing-in) – steeldriver Aug 30 '22 at 16:55
  • A list of arguments to a command must be stored in an array and in bash, all parameter expansions must be quoted. – Stéphane Chazelas Aug 30 '22 at 16:56
  • See: [How can we run a command stored in a variable?](https://unix.stackexchange.com/q/444946/170373) – ilkkachu Aug 30 '22 at 17:04
  • It looks the same if you miss the fact that the way you wrote it, the variable `$combined` contains literal quotes, which aren't there in the arguments `find` gets with `find ... -name "*.cs" ...`. So no, it's not the same. If you didn't add those quotes when appending to `combined`, it _might_ work by accident (in a directory where those globs don't match, and with Bash's `failglob` and `nullglob` disabled, and with none of those extensions containing whitespace themselves. Maybe some other requirements too). – ilkkachu Aug 30 '22 at 17:06

1 Answers1

-1

Instead of making combined a string, instead make it an array.

for ext in "${ext_allowed[@]}"; do
        combined+=($ext)
done

You will then need to use parameter expansion. (see https://wiki.bash-hackers.org/syntax/pe#search_and_replace)

find "$location" "${combined[@]/#/'-not -name '}" -not -type d
meijin3
  • 139
  • 6
  • 1
    No, `"${array[@]/#/replacement}"` will not be able to insert extra arguments. Here, you want `combined+=( ! -name "$ext" )` and `find ... "${combined[@]}"`. – Stéphane Chazelas Aug 30 '22 at 17:41
  • @StéphaneChazelas I'm not sure what you mean by my method not being able to insert extra arguments. This may be entirely due to my own ignorance. Running it through a bash interpreter, it seems to work just fine: https://ideone.com/pJHdDq – meijin3 Aug 30 '22 at 17:46
  • 2
    Your using `echo` there for which `echo '-not -name x' '-not -name x'` and `echo -not -name x -not -name x` output the same thing since `echo` joins its arguments with spaces. Try with `printf '<%s>\n'` instead of `echo` for instance. Or without the `echo` and see that `find` is failing. – Stéphane Chazelas Aug 30 '22 at 17:48
  • ```find "$location" "${combined[@]/#/'-not -name '}" -not -type d``` is not working because I need to add quotes around the array values and I do not know how to fix this in a one liner. It is a sweet solution though. – Alex Aug 30 '22 at 18:45
  • moreover, the _unquoted_ expansion of `$ext` in `combined+=($ext)` would expand the glob right then and there (if there are any matching files in the current directory). That's not what you want with `find`, you want to give it the unmodified pattern so that it can match against it in subdirectories also. – ilkkachu Aug 30 '22 at 20:29