LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   BASH: if statement in a for loop (https://www.linuxquestions.org/questions/linux-newbie-8/bash-if-statement-in-a-for-loop-4175577071/)

beca123456 04-09-2016 02:30 PM

BASH: if statement in a for loop
 
I am sure it is a very basic question, but I checked a lot of threads and could not find an answer.

For files in a directory, how to process them if their filename do NOT contain a pattern?

I tried something like this so far:
Code:

for A in /path/to/*.txt; do if [[ ls | grep -v \^pattern.\ ${A} ]] then; <command ${A}>; fi; done
I keep getting 'unexpected token ', 'syntax error near '|' or 'conditional binary operator expected' messages.

Michael Uplawski 04-09-2016 03:07 PM

Quote:

Originally Posted by beca123456 (Post 5528656)
For files in a directory, how to process them if their filename do NOT contain a pattern?

You can negate a pattern with '!', like in
Code:

for f in `ls [!pattern]*`; do echo "$f"; done
PSE tell me if this still causes problems.

beca123456 04-09-2016 03:12 PM

Awesome ! Thanks Michael !

Michael Uplawski 04-09-2016 03:24 PM

Quote:

Originally Posted by beca123456 (Post 5528666)
ls works only for the current directory, right?

That is not your real problem, you can extend my example from above to
Code:

for f in `ls /path/to/the/directory/[!file_pattern]*`; do echo "$f"; done
then call the script from wherever you like.

But if you plan to re-use this under changing conditions, it will be interesting, how you compose your pattern each time. I am not really sure, but have a bad feeling about the negation. It may introduce more potential for false “positives” than without... Maybe it is wiser to move the unwanted files away from the directory, then just process the remainder...
This is really strange; as if I had made some bad experience with such a match one time but cannot remember any more...

cnamejj 04-09-2016 05:22 PM

Here's an alternate method that might be interesting to see. It's more like how my brain works, so (at least for me) it's more readable.

Code:

for FN in $(ls /path/to/*.txt | awk '!/pattern/'); do <command ${FN}>; done
If the file names have spaces in them it won't work. I can post a minor tweak way to deal with that if there's interest.

grail 04-09-2016 06:09 PM

For both posts 2, 4 and 5 one will hope that none of the output of `` or $() is separated by white space, otherwise the command will be working on something that does not exist.

I have to say that from the original example provided I am not sure I understand the task?
Code:

ls | grep -v \^pattern.\ ${A}
The above makes little to no sense. List all items in the current directory and negate a grep on the output that does not contain '^pattern /path/to/abc.txt'. My question is why you would have
any files or directories that would contain such a pattern?

Are you able to perhaps explain, perhaps with example data, exactly what it is you are after?

cnamejj 04-09-2016 07:10 PM

To handle files with spaces in the names, this variant should work.

Code:

ls /path/to/*.txt | awk '!/pattern/' | while read FN; do <command ${FN}>; done
But I prefer to avoid having "while read" get data from a pipeline whenever possible though. I've run into problems where some commands inside the "do/done" loop can screw up the data in the pipeline, essentially terminating the loop after the first time through.

In my experience it will either work or break every time, so it's easy enough to test before you start using the script. But I still prefer to avoid that sort of construct where I can.

ntubski 04-09-2016 07:38 PM

Quote:

Originally Posted by Michael Uplawski (Post 5528664)
You can negate a pattern with '!', like in
Code:

for f in `ls [!pattern]*`; do echo "$f"; done
PSE tell me if this still causes problems.

It's a bit misleading to say that negates a pattern. The ! complements a character set, so [!pattern]* matches any file that doesn't start with one a,e,n,p,r, or t. The `ls ...` is redundant, you can get the same with
Code:

for f in [!pattern]*; do echo "$f"; done
except that this version can handle file names with spaces.
Quote:

[…]

Matches any one of the enclosed characters. ... If the first character following the ‘[’ is a ‘!’ or a ‘^’ then any character not enclosed is matched.

http://www.gnu.org/software/bash/man...-Matching.html

If you enable extglob, !(pattern-list) gives you actual pattern negation.

grail 04-09-2016 07:44 PM

cnamejj's last post seems to make it clearer what is being attempted, but I still like to keep things simple:
Code:

pattern=<regex here>

for FN in /path/to/*.txt
do
  [[ "$FN" =~ $pattern ]] || <command "$FN">
done


Michael Uplawski 04-10-2016 01:32 AM

Quote:

Originally Posted by ntubski (Post 5528770)
The ! complements a character set, so [!pattern]* matches any file that doesn't start with one a,e,n,p,r, or t.

Thank you. This distinction is important.
Quote:

If you enable extglob, !(pattern-list) gives you actual pattern negation.
The specific needs of the OP had not been too clear, in this respect. Anyway, it happens often, that we respond to a question, and many follow, before the OP explains why all our responses are “not quite what he needs”.
The original example lets much space for imagination. A temptation that I try to resist. ;)


All times are GMT -5. The time now is 09:13 AM.