Bash script : read text files using “AND” conditions with different lines

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
0
down vote

favorite












I have created simple bash script with "AND" condition but not working :



#!/bin/bash

cat log3.txt |
while read -r LINE
do
if [[ $LINE =~ Host ]] && [[ $LINE =~ denied ]] ; then echo $LINE;
fi
done


and here are content of log3.txt



Host: abcd.com
Access denied


If using OR condition it is working well, but I want to use the AND condition, so if the log contains both of the strings "Host" and "Access Denied", I will get output.










share|improve this question



























    up vote
    0
    down vote

    favorite












    I have created simple bash script with "AND" condition but not working :



    #!/bin/bash

    cat log3.txt |
    while read -r LINE
    do
    if [[ $LINE =~ Host ]] && [[ $LINE =~ denied ]] ; then echo $LINE;
    fi
    done


    and here are content of log3.txt



    Host: abcd.com
    Access denied


    If using OR condition it is working well, but I want to use the AND condition, so if the log contains both of the strings "Host" and "Access Denied", I will get output.










    share|improve this question

























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I have created simple bash script with "AND" condition but not working :



      #!/bin/bash

      cat log3.txt |
      while read -r LINE
      do
      if [[ $LINE =~ Host ]] && [[ $LINE =~ denied ]] ; then echo $LINE;
      fi
      done


      and here are content of log3.txt



      Host: abcd.com
      Access denied


      If using OR condition it is working well, but I want to use the AND condition, so if the log contains both of the strings "Host" and "Access Denied", I will get output.










      share|improve this question















      I have created simple bash script with "AND" condition but not working :



      #!/bin/bash

      cat log3.txt |
      while read -r LINE
      do
      if [[ $LINE =~ Host ]] && [[ $LINE =~ denied ]] ; then echo $LINE;
      fi
      done


      and here are content of log3.txt



      Host: abcd.com
      Access denied


      If using OR condition it is working well, but I want to use the AND condition, so if the log contains both of the strings "Host" and "Access Denied", I will get output.







      shell-script






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Dec 3 at 8:17









      Rui F Ribeiro

      38.5k1479128




      38.5k1479128










      asked Dec 3 at 6:47









      Widi Anto

      32




      32




















          3 Answers
          3






          active

          oldest

          votes

















          up vote
          0
          down vote



          accepted










          If you are sure that the files to process are small (like your example), you can read the whole file in one go and test that:



           file=$(<log3.txt)
          [[ $file =~ Host ]] && [[ $file =~ denied ]] && echo "$file"


          For a larger file, and assuming that Host comes before denied you may use a faster (for external files) sed:



           <log3.txt sed -n '/^Host/!d;p;:1;n;/<denied>/p;q;b1'


          Understand that this solution will strictly print the first line that starts with Host and the following (not in the same line) first line that contains denied as a word.



          If you need to extract several pairs of Host - denied, change the q to a b, that will re-start the cycle:



           <log3.txt sed -n '/^Host/!d;p;:1;n;/<denied>/p;b;b1'


          A similar solution with awk that will print the last Host line that is just before a denied line (in pairs):



           awk ' p==1 && /<denied>/ d=$0;p=0
          /^Host*/ h=$0;p=1
          if(p==0&&h!=""&&d!="") print h,RS,d;p=2
          ' <log3.txt


          And the same logic (except that it will match denied anywhere on the line (not as a word)) in the shell:



           #!/bin/sh
          p=0
          while IFS= read -r line; do
          if [ "$p" = 1 ]; then
          case $line in
          *denied*) deniedline=$line; p=0 ;;
          esac
          fi

          case $line in
          Host*) hostline=$line; p=1 ;;
          esac

          if [ "$p" = 0 ] && [ "$hostline" ] && [ "$deniedline" ]; then
          printf '%sn%sn' "$hostline" "$deniedline"
          p=2
          fi

          done <log3.txt





          share|improve this answer






















          • 2nd solution doesn't quite work, it prints whatever comes before the first "Host" line and hangs on this input: Host: ok.com/Access OK/Host: denied.com/Access denied.
            – xenoid
            Dec 3 at 16:44










          • Yes, the first version assumed denied followed Host (as it is written on the answer). I made it a lot more robust now. Hard for me to think of a way to break it (until someone figure out how, of course :-) ).
            – Isaac
            Dec 3 at 21:08










          • yes 2nd solution it is OR condition
            – Widi Anto
            Dec 4 at 2:54










          • and the end solution it is work for me, and it is perfect, thanks.
            – Widi Anto
            Dec 4 at 2:56

















          up vote
          2
          down vote













          In any single iteration of your while loop, the value $LINE can't be both Host and denied. It's impossible given the data in the file. This is why you get no output.



          If you want to see all lines in the file that matches the two words Host or denied, use grep instead:



          grep -wF -e 'Host' -e 'Access denied' <log3.txt


          The options used here will ensure that we are doing string comparisons rather than regular expression matches (-F) and that we are matching complete words and not substrings (-w). The two query strings are given with -e and we'll get any line containing any of these.



          If you want to make a slightly more advanced query, which only shows the lines that contains the two words if they both appear in the file, then you could do it with an awk program instead:



          awk '/Host/ hostline=$0 /Access denied/ deniedline=$0 
          END if ((hostline != "") && (deniedline != ""))
          print hostline; print deniedline; ' <log3.txt


          Here, if we find a line matching the string Host, we save it, and likewise for the string Access denied. At the end, if both strings contain anything, we print them.



          In more or less equivalent shell code:



          #!/bin/sh

          while IFS= read -r line; do
          case $line in
          *Host*)
          hostline=$line ;;
          *"Access denied"*)
          deniedline=$line ;;
          esac
          done <log3.txt

          if [ -n "$hostline" ] && [ -n "$deniedline" ]; then
          printf '%sn%sn' "$hostline" "$deniedline"
          fi


          Here I use a case ... esac statement to do the matching on the read data. The patterns used are filename globbing patterns, not regular expressions.



          Related:



          • Understanding "IFS= read -r line"

          • Why is using a shell loop to process text considered bad practice?





          share|improve this answer






















          • awk code doesn't seem to work, try with Host: denied1.com/Access denied/Host: ok.com/Access OK/Host: random.com. The question is hard to answer since we don't know what the rest of the file looks like.
            – xenoid
            Dec 3 at 9:37










          • @xenoid I've made it slightly more robust, but you are correct that the intended behaviour is unclear.
            – Kusalananda
            Dec 3 at 9:48










          • @Kusalananda thanks it works for me
            – Widi Anto
            Dec 3 at 10:12










          • Notes worth adding: The grep code will print any line with either Host or Access denied, not as pairs. The awk solution will only print the last instance of the pair. The shell solution will match Host at any position on the line and will only print the last Host and the last Access denied found.
            – Isaac
            Dec 3 at 21:43











          • @Kusalananda grep -wF -e 'Host' -e 'Access denied' <log3.txt it is OR condtions, so it works for me when using use case ... esac
            – Widi Anto
            Dec 4 at 2:29

















          up vote
          0
          down vote













          See @Kusalananda answer for why your solution doesn't work.



          My solution using grep -z:



          grep -zEo -e 'Host: (w|.)+s+Access denieds' log.txt


          In slo-mo:




          • -E: use extended regexp


          • -o: print matches only


          • -z: use as line delimiters. Since there are none, the search is done on the whole file, where n is just a plain character.


          • - e'Host: (w|.)+s+Access denieds': look for:

            • "Host:"

            • A sequence of letter, digits, or dots

            • A space-class character (which is going to be n)

            • "Access denied"

            • A space-class character (which is going to be n). This one is need to get a linefeed on output


          Running on:



          Host: denied1.com
          Access denied
          Host: ok.com
          Access OK
          Host: random.com

          Host: denied2.com
          Access denied

          More stuff


          Yields:



          Host: denied1.com
          Access denied
          Host: denied2.com
          Access denied





          share|improve this answer




















          • this is not work for me, there'is no results after running the command
            – Widi Anto
            Dec 4 at 2:58










          • What is the input? Works for me with your two-lines data if the last line ends with a linefeed (like all Linux logs do). If you want to the command to work even it if it is missing, just add a ? at the end of the regexp: 'Host: (w|.)+sAccess denieds?'
            – xenoid
            Dec 4 at 7:41











          Your Answer








          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "106"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f485613%2fbash-script-read-text-files-using-and-conditions-with-different-lines%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          3 Answers
          3






          active

          oldest

          votes








          3 Answers
          3






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          0
          down vote



          accepted










          If you are sure that the files to process are small (like your example), you can read the whole file in one go and test that:



           file=$(<log3.txt)
          [[ $file =~ Host ]] && [[ $file =~ denied ]] && echo "$file"


          For a larger file, and assuming that Host comes before denied you may use a faster (for external files) sed:



           <log3.txt sed -n '/^Host/!d;p;:1;n;/<denied>/p;q;b1'


          Understand that this solution will strictly print the first line that starts with Host and the following (not in the same line) first line that contains denied as a word.



          If you need to extract several pairs of Host - denied, change the q to a b, that will re-start the cycle:



           <log3.txt sed -n '/^Host/!d;p;:1;n;/<denied>/p;b;b1'


          A similar solution with awk that will print the last Host line that is just before a denied line (in pairs):



           awk ' p==1 && /<denied>/ d=$0;p=0
          /^Host*/ h=$0;p=1
          if(p==0&&h!=""&&d!="") print h,RS,d;p=2
          ' <log3.txt


          And the same logic (except that it will match denied anywhere on the line (not as a word)) in the shell:



           #!/bin/sh
          p=0
          while IFS= read -r line; do
          if [ "$p" = 1 ]; then
          case $line in
          *denied*) deniedline=$line; p=0 ;;
          esac
          fi

          case $line in
          Host*) hostline=$line; p=1 ;;
          esac

          if [ "$p" = 0 ] && [ "$hostline" ] && [ "$deniedline" ]; then
          printf '%sn%sn' "$hostline" "$deniedline"
          p=2
          fi

          done <log3.txt





          share|improve this answer






















          • 2nd solution doesn't quite work, it prints whatever comes before the first "Host" line and hangs on this input: Host: ok.com/Access OK/Host: denied.com/Access denied.
            – xenoid
            Dec 3 at 16:44










          • Yes, the first version assumed denied followed Host (as it is written on the answer). I made it a lot more robust now. Hard for me to think of a way to break it (until someone figure out how, of course :-) ).
            – Isaac
            Dec 3 at 21:08










          • yes 2nd solution it is OR condition
            – Widi Anto
            Dec 4 at 2:54










          • and the end solution it is work for me, and it is perfect, thanks.
            – Widi Anto
            Dec 4 at 2:56














          up vote
          0
          down vote



          accepted










          If you are sure that the files to process are small (like your example), you can read the whole file in one go and test that:



           file=$(<log3.txt)
          [[ $file =~ Host ]] && [[ $file =~ denied ]] && echo "$file"


          For a larger file, and assuming that Host comes before denied you may use a faster (for external files) sed:



           <log3.txt sed -n '/^Host/!d;p;:1;n;/<denied>/p;q;b1'


          Understand that this solution will strictly print the first line that starts with Host and the following (not in the same line) first line that contains denied as a word.



          If you need to extract several pairs of Host - denied, change the q to a b, that will re-start the cycle:



           <log3.txt sed -n '/^Host/!d;p;:1;n;/<denied>/p;b;b1'


          A similar solution with awk that will print the last Host line that is just before a denied line (in pairs):



           awk ' p==1 && /<denied>/ d=$0;p=0
          /^Host*/ h=$0;p=1
          if(p==0&&h!=""&&d!="") print h,RS,d;p=2
          ' <log3.txt


          And the same logic (except that it will match denied anywhere on the line (not as a word)) in the shell:



           #!/bin/sh
          p=0
          while IFS= read -r line; do
          if [ "$p" = 1 ]; then
          case $line in
          *denied*) deniedline=$line; p=0 ;;
          esac
          fi

          case $line in
          Host*) hostline=$line; p=1 ;;
          esac

          if [ "$p" = 0 ] && [ "$hostline" ] && [ "$deniedline" ]; then
          printf '%sn%sn' "$hostline" "$deniedline"
          p=2
          fi

          done <log3.txt





          share|improve this answer






















          • 2nd solution doesn't quite work, it prints whatever comes before the first "Host" line and hangs on this input: Host: ok.com/Access OK/Host: denied.com/Access denied.
            – xenoid
            Dec 3 at 16:44










          • Yes, the first version assumed denied followed Host (as it is written on the answer). I made it a lot more robust now. Hard for me to think of a way to break it (until someone figure out how, of course :-) ).
            – Isaac
            Dec 3 at 21:08










          • yes 2nd solution it is OR condition
            – Widi Anto
            Dec 4 at 2:54










          • and the end solution it is work for me, and it is perfect, thanks.
            – Widi Anto
            Dec 4 at 2:56












          up vote
          0
          down vote



          accepted







          up vote
          0
          down vote



          accepted






          If you are sure that the files to process are small (like your example), you can read the whole file in one go and test that:



           file=$(<log3.txt)
          [[ $file =~ Host ]] && [[ $file =~ denied ]] && echo "$file"


          For a larger file, and assuming that Host comes before denied you may use a faster (for external files) sed:



           <log3.txt sed -n '/^Host/!d;p;:1;n;/<denied>/p;q;b1'


          Understand that this solution will strictly print the first line that starts with Host and the following (not in the same line) first line that contains denied as a word.



          If you need to extract several pairs of Host - denied, change the q to a b, that will re-start the cycle:



           <log3.txt sed -n '/^Host/!d;p;:1;n;/<denied>/p;b;b1'


          A similar solution with awk that will print the last Host line that is just before a denied line (in pairs):



           awk ' p==1 && /<denied>/ d=$0;p=0
          /^Host*/ h=$0;p=1
          if(p==0&&h!=""&&d!="") print h,RS,d;p=2
          ' <log3.txt


          And the same logic (except that it will match denied anywhere on the line (not as a word)) in the shell:



           #!/bin/sh
          p=0
          while IFS= read -r line; do
          if [ "$p" = 1 ]; then
          case $line in
          *denied*) deniedline=$line; p=0 ;;
          esac
          fi

          case $line in
          Host*) hostline=$line; p=1 ;;
          esac

          if [ "$p" = 0 ] && [ "$hostline" ] && [ "$deniedline" ]; then
          printf '%sn%sn' "$hostline" "$deniedline"
          p=2
          fi

          done <log3.txt





          share|improve this answer














          If you are sure that the files to process are small (like your example), you can read the whole file in one go and test that:



           file=$(<log3.txt)
          [[ $file =~ Host ]] && [[ $file =~ denied ]] && echo "$file"


          For a larger file, and assuming that Host comes before denied you may use a faster (for external files) sed:



           <log3.txt sed -n '/^Host/!d;p;:1;n;/<denied>/p;q;b1'


          Understand that this solution will strictly print the first line that starts with Host and the following (not in the same line) first line that contains denied as a word.



          If you need to extract several pairs of Host - denied, change the q to a b, that will re-start the cycle:



           <log3.txt sed -n '/^Host/!d;p;:1;n;/<denied>/p;b;b1'


          A similar solution with awk that will print the last Host line that is just before a denied line (in pairs):



           awk ' p==1 && /<denied>/ d=$0;p=0
          /^Host*/ h=$0;p=1
          if(p==0&&h!=""&&d!="") print h,RS,d;p=2
          ' <log3.txt


          And the same logic (except that it will match denied anywhere on the line (not as a word)) in the shell:



           #!/bin/sh
          p=0
          while IFS= read -r line; do
          if [ "$p" = 1 ]; then
          case $line in
          *denied*) deniedline=$line; p=0 ;;
          esac
          fi

          case $line in
          Host*) hostline=$line; p=1 ;;
          esac

          if [ "$p" = 0 ] && [ "$hostline" ] && [ "$deniedline" ]; then
          printf '%sn%sn' "$hostline" "$deniedline"
          p=2
          fi

          done <log3.txt






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 4 at 2:59

























          answered Dec 3 at 10:23









          Isaac

          10.9k11448




          10.9k11448











          • 2nd solution doesn't quite work, it prints whatever comes before the first "Host" line and hangs on this input: Host: ok.com/Access OK/Host: denied.com/Access denied.
            – xenoid
            Dec 3 at 16:44










          • Yes, the first version assumed denied followed Host (as it is written on the answer). I made it a lot more robust now. Hard for me to think of a way to break it (until someone figure out how, of course :-) ).
            – Isaac
            Dec 3 at 21:08










          • yes 2nd solution it is OR condition
            – Widi Anto
            Dec 4 at 2:54










          • and the end solution it is work for me, and it is perfect, thanks.
            – Widi Anto
            Dec 4 at 2:56
















          • 2nd solution doesn't quite work, it prints whatever comes before the first "Host" line and hangs on this input: Host: ok.com/Access OK/Host: denied.com/Access denied.
            – xenoid
            Dec 3 at 16:44










          • Yes, the first version assumed denied followed Host (as it is written on the answer). I made it a lot more robust now. Hard for me to think of a way to break it (until someone figure out how, of course :-) ).
            – Isaac
            Dec 3 at 21:08










          • yes 2nd solution it is OR condition
            – Widi Anto
            Dec 4 at 2:54










          • and the end solution it is work for me, and it is perfect, thanks.
            – Widi Anto
            Dec 4 at 2:56















          2nd solution doesn't quite work, it prints whatever comes before the first "Host" line and hangs on this input: Host: ok.com/Access OK/Host: denied.com/Access denied.
          – xenoid
          Dec 3 at 16:44




          2nd solution doesn't quite work, it prints whatever comes before the first "Host" line and hangs on this input: Host: ok.com/Access OK/Host: denied.com/Access denied.
          – xenoid
          Dec 3 at 16:44












          Yes, the first version assumed denied followed Host (as it is written on the answer). I made it a lot more robust now. Hard for me to think of a way to break it (until someone figure out how, of course :-) ).
          – Isaac
          Dec 3 at 21:08




          Yes, the first version assumed denied followed Host (as it is written on the answer). I made it a lot more robust now. Hard for me to think of a way to break it (until someone figure out how, of course :-) ).
          – Isaac
          Dec 3 at 21:08












          yes 2nd solution it is OR condition
          – Widi Anto
          Dec 4 at 2:54




          yes 2nd solution it is OR condition
          – Widi Anto
          Dec 4 at 2:54












          and the end solution it is work for me, and it is perfect, thanks.
          – Widi Anto
          Dec 4 at 2:56




          and the end solution it is work for me, and it is perfect, thanks.
          – Widi Anto
          Dec 4 at 2:56












          up vote
          2
          down vote













          In any single iteration of your while loop, the value $LINE can't be both Host and denied. It's impossible given the data in the file. This is why you get no output.



          If you want to see all lines in the file that matches the two words Host or denied, use grep instead:



          grep -wF -e 'Host' -e 'Access denied' <log3.txt


          The options used here will ensure that we are doing string comparisons rather than regular expression matches (-F) and that we are matching complete words and not substrings (-w). The two query strings are given with -e and we'll get any line containing any of these.



          If you want to make a slightly more advanced query, which only shows the lines that contains the two words if they both appear in the file, then you could do it with an awk program instead:



          awk '/Host/ hostline=$0 /Access denied/ deniedline=$0 
          END if ((hostline != "") && (deniedline != ""))
          print hostline; print deniedline; ' <log3.txt


          Here, if we find a line matching the string Host, we save it, and likewise for the string Access denied. At the end, if both strings contain anything, we print them.



          In more or less equivalent shell code:



          #!/bin/sh

          while IFS= read -r line; do
          case $line in
          *Host*)
          hostline=$line ;;
          *"Access denied"*)
          deniedline=$line ;;
          esac
          done <log3.txt

          if [ -n "$hostline" ] && [ -n "$deniedline" ]; then
          printf '%sn%sn' "$hostline" "$deniedline"
          fi


          Here I use a case ... esac statement to do the matching on the read data. The patterns used are filename globbing patterns, not regular expressions.



          Related:



          • Understanding "IFS= read -r line"

          • Why is using a shell loop to process text considered bad practice?





          share|improve this answer






















          • awk code doesn't seem to work, try with Host: denied1.com/Access denied/Host: ok.com/Access OK/Host: random.com. The question is hard to answer since we don't know what the rest of the file looks like.
            – xenoid
            Dec 3 at 9:37










          • @xenoid I've made it slightly more robust, but you are correct that the intended behaviour is unclear.
            – Kusalananda
            Dec 3 at 9:48










          • @Kusalananda thanks it works for me
            – Widi Anto
            Dec 3 at 10:12










          • Notes worth adding: The grep code will print any line with either Host or Access denied, not as pairs. The awk solution will only print the last instance of the pair. The shell solution will match Host at any position on the line and will only print the last Host and the last Access denied found.
            – Isaac
            Dec 3 at 21:43











          • @Kusalananda grep -wF -e 'Host' -e 'Access denied' <log3.txt it is OR condtions, so it works for me when using use case ... esac
            – Widi Anto
            Dec 4 at 2:29














          up vote
          2
          down vote













          In any single iteration of your while loop, the value $LINE can't be both Host and denied. It's impossible given the data in the file. This is why you get no output.



          If you want to see all lines in the file that matches the two words Host or denied, use grep instead:



          grep -wF -e 'Host' -e 'Access denied' <log3.txt


          The options used here will ensure that we are doing string comparisons rather than regular expression matches (-F) and that we are matching complete words and not substrings (-w). The two query strings are given with -e and we'll get any line containing any of these.



          If you want to make a slightly more advanced query, which only shows the lines that contains the two words if they both appear in the file, then you could do it with an awk program instead:



          awk '/Host/ hostline=$0 /Access denied/ deniedline=$0 
          END if ((hostline != "") && (deniedline != ""))
          print hostline; print deniedline; ' <log3.txt


          Here, if we find a line matching the string Host, we save it, and likewise for the string Access denied. At the end, if both strings contain anything, we print them.



          In more or less equivalent shell code:



          #!/bin/sh

          while IFS= read -r line; do
          case $line in
          *Host*)
          hostline=$line ;;
          *"Access denied"*)
          deniedline=$line ;;
          esac
          done <log3.txt

          if [ -n "$hostline" ] && [ -n "$deniedline" ]; then
          printf '%sn%sn' "$hostline" "$deniedline"
          fi


          Here I use a case ... esac statement to do the matching on the read data. The patterns used are filename globbing patterns, not regular expressions.



          Related:



          • Understanding "IFS= read -r line"

          • Why is using a shell loop to process text considered bad practice?





          share|improve this answer






















          • awk code doesn't seem to work, try with Host: denied1.com/Access denied/Host: ok.com/Access OK/Host: random.com. The question is hard to answer since we don't know what the rest of the file looks like.
            – xenoid
            Dec 3 at 9:37










          • @xenoid I've made it slightly more robust, but you are correct that the intended behaviour is unclear.
            – Kusalananda
            Dec 3 at 9:48










          • @Kusalananda thanks it works for me
            – Widi Anto
            Dec 3 at 10:12










          • Notes worth adding: The grep code will print any line with either Host or Access denied, not as pairs. The awk solution will only print the last instance of the pair. The shell solution will match Host at any position on the line and will only print the last Host and the last Access denied found.
            – Isaac
            Dec 3 at 21:43











          • @Kusalananda grep -wF -e 'Host' -e 'Access denied' <log3.txt it is OR condtions, so it works for me when using use case ... esac
            – Widi Anto
            Dec 4 at 2:29












          up vote
          2
          down vote










          up vote
          2
          down vote









          In any single iteration of your while loop, the value $LINE can't be both Host and denied. It's impossible given the data in the file. This is why you get no output.



          If you want to see all lines in the file that matches the two words Host or denied, use grep instead:



          grep -wF -e 'Host' -e 'Access denied' <log3.txt


          The options used here will ensure that we are doing string comparisons rather than regular expression matches (-F) and that we are matching complete words and not substrings (-w). The two query strings are given with -e and we'll get any line containing any of these.



          If you want to make a slightly more advanced query, which only shows the lines that contains the two words if they both appear in the file, then you could do it with an awk program instead:



          awk '/Host/ hostline=$0 /Access denied/ deniedline=$0 
          END if ((hostline != "") && (deniedline != ""))
          print hostline; print deniedline; ' <log3.txt


          Here, if we find a line matching the string Host, we save it, and likewise for the string Access denied. At the end, if both strings contain anything, we print them.



          In more or less equivalent shell code:



          #!/bin/sh

          while IFS= read -r line; do
          case $line in
          *Host*)
          hostline=$line ;;
          *"Access denied"*)
          deniedline=$line ;;
          esac
          done <log3.txt

          if [ -n "$hostline" ] && [ -n "$deniedline" ]; then
          printf '%sn%sn' "$hostline" "$deniedline"
          fi


          Here I use a case ... esac statement to do the matching on the read data. The patterns used are filename globbing patterns, not regular expressions.



          Related:



          • Understanding "IFS= read -r line"

          • Why is using a shell loop to process text considered bad practice?





          share|improve this answer














          In any single iteration of your while loop, the value $LINE can't be both Host and denied. It's impossible given the data in the file. This is why you get no output.



          If you want to see all lines in the file that matches the two words Host or denied, use grep instead:



          grep -wF -e 'Host' -e 'Access denied' <log3.txt


          The options used here will ensure that we are doing string comparisons rather than regular expression matches (-F) and that we are matching complete words and not substrings (-w). The two query strings are given with -e and we'll get any line containing any of these.



          If you want to make a slightly more advanced query, which only shows the lines that contains the two words if they both appear in the file, then you could do it with an awk program instead:



          awk '/Host/ hostline=$0 /Access denied/ deniedline=$0 
          END if ((hostline != "") && (deniedline != ""))
          print hostline; print deniedline; ' <log3.txt


          Here, if we find a line matching the string Host, we save it, and likewise for the string Access denied. At the end, if both strings contain anything, we print them.



          In more or less equivalent shell code:



          #!/bin/sh

          while IFS= read -r line; do
          case $line in
          *Host*)
          hostline=$line ;;
          *"Access denied"*)
          deniedline=$line ;;
          esac
          done <log3.txt

          if [ -n "$hostline" ] && [ -n "$deniedline" ]; then
          printf '%sn%sn' "$hostline" "$deniedline"
          fi


          Here I use a case ... esac statement to do the matching on the read data. The patterns used are filename globbing patterns, not regular expressions.



          Related:



          • Understanding "IFS= read -r line"

          • Why is using a shell loop to process text considered bad practice?






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 3 at 9:47

























          answered Dec 3 at 7:31









          Kusalananda

          119k16223365




          119k16223365











          • awk code doesn't seem to work, try with Host: denied1.com/Access denied/Host: ok.com/Access OK/Host: random.com. The question is hard to answer since we don't know what the rest of the file looks like.
            – xenoid
            Dec 3 at 9:37










          • @xenoid I've made it slightly more robust, but you are correct that the intended behaviour is unclear.
            – Kusalananda
            Dec 3 at 9:48










          • @Kusalananda thanks it works for me
            – Widi Anto
            Dec 3 at 10:12










          • Notes worth adding: The grep code will print any line with either Host or Access denied, not as pairs. The awk solution will only print the last instance of the pair. The shell solution will match Host at any position on the line and will only print the last Host and the last Access denied found.
            – Isaac
            Dec 3 at 21:43











          • @Kusalananda grep -wF -e 'Host' -e 'Access denied' <log3.txt it is OR condtions, so it works for me when using use case ... esac
            – Widi Anto
            Dec 4 at 2:29
















          • awk code doesn't seem to work, try with Host: denied1.com/Access denied/Host: ok.com/Access OK/Host: random.com. The question is hard to answer since we don't know what the rest of the file looks like.
            – xenoid
            Dec 3 at 9:37










          • @xenoid I've made it slightly more robust, but you are correct that the intended behaviour is unclear.
            – Kusalananda
            Dec 3 at 9:48










          • @Kusalananda thanks it works for me
            – Widi Anto
            Dec 3 at 10:12










          • Notes worth adding: The grep code will print any line with either Host or Access denied, not as pairs. The awk solution will only print the last instance of the pair. The shell solution will match Host at any position on the line and will only print the last Host and the last Access denied found.
            – Isaac
            Dec 3 at 21:43











          • @Kusalananda grep -wF -e 'Host' -e 'Access denied' <log3.txt it is OR condtions, so it works for me when using use case ... esac
            – Widi Anto
            Dec 4 at 2:29















          awk code doesn't seem to work, try with Host: denied1.com/Access denied/Host: ok.com/Access OK/Host: random.com. The question is hard to answer since we don't know what the rest of the file looks like.
          – xenoid
          Dec 3 at 9:37




          awk code doesn't seem to work, try with Host: denied1.com/Access denied/Host: ok.com/Access OK/Host: random.com. The question is hard to answer since we don't know what the rest of the file looks like.
          – xenoid
          Dec 3 at 9:37












          @xenoid I've made it slightly more robust, but you are correct that the intended behaviour is unclear.
          – Kusalananda
          Dec 3 at 9:48




          @xenoid I've made it slightly more robust, but you are correct that the intended behaviour is unclear.
          – Kusalananda
          Dec 3 at 9:48












          @Kusalananda thanks it works for me
          – Widi Anto
          Dec 3 at 10:12




          @Kusalananda thanks it works for me
          – Widi Anto
          Dec 3 at 10:12












          Notes worth adding: The grep code will print any line with either Host or Access denied, not as pairs. The awk solution will only print the last instance of the pair. The shell solution will match Host at any position on the line and will only print the last Host and the last Access denied found.
          – Isaac
          Dec 3 at 21:43





          Notes worth adding: The grep code will print any line with either Host or Access denied, not as pairs. The awk solution will only print the last instance of the pair. The shell solution will match Host at any position on the line and will only print the last Host and the last Access denied found.
          – Isaac
          Dec 3 at 21:43













          @Kusalananda grep -wF -e 'Host' -e 'Access denied' <log3.txt it is OR condtions, so it works for me when using use case ... esac
          – Widi Anto
          Dec 4 at 2:29




          @Kusalananda grep -wF -e 'Host' -e 'Access denied' <log3.txt it is OR condtions, so it works for me when using use case ... esac
          – Widi Anto
          Dec 4 at 2:29










          up vote
          0
          down vote













          See @Kusalananda answer for why your solution doesn't work.



          My solution using grep -z:



          grep -zEo -e 'Host: (w|.)+s+Access denieds' log.txt


          In slo-mo:




          • -E: use extended regexp


          • -o: print matches only


          • -z: use as line delimiters. Since there are none, the search is done on the whole file, where n is just a plain character.


          • - e'Host: (w|.)+s+Access denieds': look for:

            • "Host:"

            • A sequence of letter, digits, or dots

            • A space-class character (which is going to be n)

            • "Access denied"

            • A space-class character (which is going to be n). This one is need to get a linefeed on output


          Running on:



          Host: denied1.com
          Access denied
          Host: ok.com
          Access OK
          Host: random.com

          Host: denied2.com
          Access denied

          More stuff


          Yields:



          Host: denied1.com
          Access denied
          Host: denied2.com
          Access denied





          share|improve this answer




















          • this is not work for me, there'is no results after running the command
            – Widi Anto
            Dec 4 at 2:58










          • What is the input? Works for me with your two-lines data if the last line ends with a linefeed (like all Linux logs do). If you want to the command to work even it if it is missing, just add a ? at the end of the regexp: 'Host: (w|.)+sAccess denieds?'
            – xenoid
            Dec 4 at 7:41















          up vote
          0
          down vote













          See @Kusalananda answer for why your solution doesn't work.



          My solution using grep -z:



          grep -zEo -e 'Host: (w|.)+s+Access denieds' log.txt


          In slo-mo:




          • -E: use extended regexp


          • -o: print matches only


          • -z: use as line delimiters. Since there are none, the search is done on the whole file, where n is just a plain character.


          • - e'Host: (w|.)+s+Access denieds': look for:

            • "Host:"

            • A sequence of letter, digits, or dots

            • A space-class character (which is going to be n)

            • "Access denied"

            • A space-class character (which is going to be n). This one is need to get a linefeed on output


          Running on:



          Host: denied1.com
          Access denied
          Host: ok.com
          Access OK
          Host: random.com

          Host: denied2.com
          Access denied

          More stuff


          Yields:



          Host: denied1.com
          Access denied
          Host: denied2.com
          Access denied





          share|improve this answer




















          • this is not work for me, there'is no results after running the command
            – Widi Anto
            Dec 4 at 2:58










          • What is the input? Works for me with your two-lines data if the last line ends with a linefeed (like all Linux logs do). If you want to the command to work even it if it is missing, just add a ? at the end of the regexp: 'Host: (w|.)+sAccess denieds?'
            – xenoid
            Dec 4 at 7:41













          up vote
          0
          down vote










          up vote
          0
          down vote









          See @Kusalananda answer for why your solution doesn't work.



          My solution using grep -z:



          grep -zEo -e 'Host: (w|.)+s+Access denieds' log.txt


          In slo-mo:




          • -E: use extended regexp


          • -o: print matches only


          • -z: use as line delimiters. Since there are none, the search is done on the whole file, where n is just a plain character.


          • - e'Host: (w|.)+s+Access denieds': look for:

            • "Host:"

            • A sequence of letter, digits, or dots

            • A space-class character (which is going to be n)

            • "Access denied"

            • A space-class character (which is going to be n). This one is need to get a linefeed on output


          Running on:



          Host: denied1.com
          Access denied
          Host: ok.com
          Access OK
          Host: random.com

          Host: denied2.com
          Access denied

          More stuff


          Yields:



          Host: denied1.com
          Access denied
          Host: denied2.com
          Access denied





          share|improve this answer












          See @Kusalananda answer for why your solution doesn't work.



          My solution using grep -z:



          grep -zEo -e 'Host: (w|.)+s+Access denieds' log.txt


          In slo-mo:




          • -E: use extended regexp


          • -o: print matches only


          • -z: use as line delimiters. Since there are none, the search is done on the whole file, where n is just a plain character.


          • - e'Host: (w|.)+s+Access denieds': look for:

            • "Host:"

            • A sequence of letter, digits, or dots

            • A space-class character (which is going to be n)

            • "Access denied"

            • A space-class character (which is going to be n). This one is need to get a linefeed on output


          Running on:



          Host: denied1.com
          Access denied
          Host: ok.com
          Access OK
          Host: random.com

          Host: denied2.com
          Access denied

          More stuff


          Yields:



          Host: denied1.com
          Access denied
          Host: denied2.com
          Access denied






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Dec 3 at 16:38









          xenoid

          2,6701724




          2,6701724











          • this is not work for me, there'is no results after running the command
            – Widi Anto
            Dec 4 at 2:58










          • What is the input? Works for me with your two-lines data if the last line ends with a linefeed (like all Linux logs do). If you want to the command to work even it if it is missing, just add a ? at the end of the regexp: 'Host: (w|.)+sAccess denieds?'
            – xenoid
            Dec 4 at 7:41

















          • this is not work for me, there'is no results after running the command
            – Widi Anto
            Dec 4 at 2:58










          • What is the input? Works for me with your two-lines data if the last line ends with a linefeed (like all Linux logs do). If you want to the command to work even it if it is missing, just add a ? at the end of the regexp: 'Host: (w|.)+sAccess denieds?'
            – xenoid
            Dec 4 at 7:41
















          this is not work for me, there'is no results after running the command
          – Widi Anto
          Dec 4 at 2:58




          this is not work for me, there'is no results after running the command
          – Widi Anto
          Dec 4 at 2:58












          What is the input? Works for me with your two-lines data if the last line ends with a linefeed (like all Linux logs do). If you want to the command to work even it if it is missing, just add a ? at the end of the regexp: 'Host: (w|.)+sAccess denieds?'
          – xenoid
          Dec 4 at 7:41





          What is the input? Works for me with your two-lines data if the last line ends with a linefeed (like all Linux logs do). If you want to the command to work even it if it is missing, just add a ? at the end of the regexp: 'Host: (w|.)+sAccess denieds?'
          – xenoid
          Dec 4 at 7:41


















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Unix & Linux Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f485613%2fbash-script-read-text-files-using-and-conditions-with-different-lines%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown