0

I have a simple for-loop that iterates over a glob-pattern and enters an if condition, for when the directory path is not equal to */venv then print the file. How can I get this working in the if statement?

For example:

for file in ML*/*; do if [ "$file" != */venv ]; then echo $file ; fi; done 

Is what I have tried, but it prints out:

[: too many arguments
[: too many arguments
[: too many arguments
[: too many arguments
[: too many arguments
[: too many arguments
[: too many arguments
[: too many arguments
[: too many arguments
[: too many arguments
...
...

The following implementation works for */venv:

for file in ML*/*; do if [[ "$file" != */venv]]; then find $file ; fi; done

And if I wanted to exclude multiple paths:

for file in ML*/*; do if [[ "$file" != */venv && "$file" != */ENV_DIR ]]; then find $file ; fi; done

However, this assumes only the inner directory. If I wanted to exclude all sub-directories that may have venv or ENV_DIR so */*/venv, */*/*/venv etc ..., how do I take this into consideration?

I have attempted the above with the following:

for file in ML*/*;
do for innerFile in $file*/*;
 do if [[ "$innerFile" != */venv && "$innerFile" != */ENV_DIR && "$file" != */venv && "$file" != */ENV_DIR ]];
  then find $innerFile ; fi;  done; done

However, the nested loop only return inner-subdirectories, therefore $file is skipped and we only get $file*/* paths, but for further nested files like ML/plot/something/distant/venv this won't be captured and I'd have to nest even further. What is the most effective way to capture this nested exclusion?

The below solution does not work and still will include venv, or other directories that I want excluded. I found that the following works:

find ML*/* -not -path "*/venv/**"  -not -path "*/ENV_DIR/**" -print0 | while read -d $'\0' file; do if [[ "$file" != */venv && "$file" != */ENV_DIR ]]; then echo $file; fi; done

This will only return the subdirectories and those files which do not contain venv or ENV_DIR, therefore, completing my previous proposal.

However, when I change echo $file to find $file the excluded directory path appears for ENV_DIR and I am not sure why because the IF condition should of removed it.

Emil11
  • 199
  • 9
  • 3
    Use `[[ $file != */venv ]]` instead of `[ "$file" != */venv ]`. See [BashFAQ/031](https://mywiki.wooledge.org/BashFAQ/031) – M. Nejat Aydin Dec 31 '22 at 15:25
  • Add some cases to your question (**no** comment) where $file should match and where not. – Cyrus Dec 31 '22 at 15:26
  • @Cyrus `cases` will be my next attempt after learning how `if` statements are properly implemented – Emil11 Dec 31 '22 at 15:31
  • 1
    @Emil11 Note that the `[` vs. `[[` issue has nothing to do with `if` statements. – M. Nejat Aydin Dec 31 '22 at 15:35
  • @M.NejatAydin How do I instantiate an `OR` condition for example If I wanted it to not equal two different patterns such as ```[[ "$file" != (*/venv | */ENV_DIR) ]]```, this will give `venv` files but not `ENV_DIR`, whats the correct implementation – Emil11 Dec 31 '22 at 15:36
  • @M.NejatAydin Right, this [article](https://unix.stackexchange.com/questions/306111/what-is-the-difference-between-the-bash-operators-vs-vs-vs) suggests it enables the matching of wild-card patterns which is what I needed – Emil11 Dec 31 '22 at 15:38
  • @M.NejatAydin I figured this was the only alternative, I had imagined there was a one-liner! – Emil11 Dec 31 '22 at 15:44
  • BTW, one often would use a `case` statement here. `case $file in */venv|*/ENV_DIR) :;; *) echo "$file";; esac` works not just in bash but also in POSIX sh, which doesn't support `[[` or extglobs. – Charles Duffy Dec 31 '22 at 16:05

0 Answers0