Bash Conditional connection, with wildcards and checking for files

I mastered the basics of Bash compound conditional expressions and read several different ways to check for the presence of a wildcard file, but that eluded me, so I decided I would ask for help ..

I need: 1.) Check if there is any file that matches pattern A ALSO 2.) Check if the text exists in another file.

I know that there are many ways to do this, but I really do not have the knowledge to prioritize (if you have this knowledge, I would also be interested to read about it).

The first things that came to mind is to use find for # 1 and grep for # 2

So something like

if [ `grep -q "OUTPUT FILE AT STEP 1000" ../log/minimize.log` ] \ && [ `find -name "jobscript_minim\*cmd\*o\*"` ]; then echo "Both passed! (1)" fi 

This fails, though with curiosity:

 if `grep -q "OUTPUT FILE AT STEP 1000" ../log/minimize.log` ;then echo "Text passed!" fi if `find -name "jobscript_minim\*cmd\*o\*"` ;then echo "File passed!" fi 

both pass ...

I read a bit and saw people talking about a problem with multiple file names corresponding to wildcards in an if statement. What is the best solution? (answering my question, I assumed that you also cracked this question in the process)

Any ideas / solutions / suggestions?

+4
source share
3 answers

Let me decide why your attempt failed in the first place:

 if [ `grep -q …` ]; 

Executes the grep between callbacks and interpolates the output inside the conditional command. Since grep -q produces no output, it seems to write if [ ];

The condition is supposed to check the grep return code, and not something about its output. Therefore, it should simply be written as

 if grep -q …; 

The find returns 0 (i.e. true), even if it does not find anything, so this method will not work. That will work by checking if its output is empty, collecting its output, comparing it with an empty string:

 if [ "$(find …)" != "" ]; 

(equivalent test if [ -n "$(find …)" ] .)

Pay attention to two things:

  • I used $(…) instead of backlinks. They are equivalent, except that backticks require weird quoting inside them (especially if you are trying to nest them), while $(…) is simple and reliable. Just use $(…) and forget about backticks (except that you need to write \` inside double quotes).

  • There are double quotes in $(…) . This is really important. Without quotes, the shell broke the output of the find into words. If find prints, say, two lines dir/file and dir/otherfile , we want to execute if [ "dir/file dir/otherfile" = "" ]; , not if [ dir/file dir/otherfile = "" ]; , which is a syntax error. This is a general rule of shell programming: always put double quotes around a variable or command substitution . (Substitution of variables $foo or ${foo} , substitution of the command $(command) .)


Now let's see your requirements.

  • Check if there is any file matching the pattern

    If you are looking for files in the current directory or in any directory below it recursively, then find -name "PATTERN" right. However, if the directory tree can become large, it is inefficient because it can spend a lot of time printing all matches when we only care about that. Easy optimization is to save only the first line using the pipe in head -n 1 ; find stop searching if it realizes that head no longer interested in what it has to say.

    if ["$ (find -name" jobscript_minimcmdo "| head -n 1)"! = ""];

    (Note that double quotes already protect wildcards from expansion.)

    If you are looking for files in the current directory, assuming you have GNU find (which is the case on Linux, Cygwin, and Gnuwin32), a simple solution is to say that it will not process deeper than the current directory.

    if ["$ (find -maxdepth 1 -name" jobscript_minim * cmd * o * ")"! = ""];

    There are other solutions that are more portable, but harder to write.

  • Check if text exists in another file.

    You already have the correct grep . Note that if you want to find a literal string, you must use grep -F ; if you are looking for a regular expression, grep -E has a simpler syntax than regular grep .

Putting it all together:

 if grep -q -F "OUTPUT FILE AT STEP 1000" ../log/minimize.log && [ "$(find -name "jobscript_minim*cmd*o*")" != "" ]; then echo "Both passed! (1)" fi 
+10
source

bash 4

 shopt -s globstar files=$(echo **/jobscript_minim*cmd*o*) if grep -q "pattern" file && [[ ! -z $files ]];then echo "passed"; fi 
0
source
 for i in filename*; do FOUND=$i;break;done if [ $FOUND == 'filename*' ]; then echo "No files found matching wildcard." else echo "Files found matching wildcard." fi 
0
source

All Articles