How do you construct a grep & command to match a number of patterns depending on how many are provided at runtime?

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












4















I have exported some MS Word documents to plain text and use this function to parse the contents of the .txt files in the current directory:



mo1 () 
for i in *.txt; do
echo "File: $i"
grep -n -HC 1 "$@" "$i"
done



If I had more than one pattern to look for, I could do mo1 | grep pattern2. But what if I want to do something the result of which would be like grep -E 'pattern1.*pattern2[.*...]...' depending on how many patterns are supplied to the function at runtime i.e. mo1 pattern1 pattern2 [...] etc.? I can see the @ array could provide the number of items and I could construct over a loop a variable (finalpattern='$1.*$2.*$3') that would end up being the expression used for grep. But I can't think of how to abstract that bit where you craft the expression in the function? Or is there a better/simpler way to do something like this?










share|improve this question


























    4















    I have exported some MS Word documents to plain text and use this function to parse the contents of the .txt files in the current directory:



    mo1 () 
    for i in *.txt; do
    echo "File: $i"
    grep -n -HC 1 "$@" "$i"
    done



    If I had more than one pattern to look for, I could do mo1 | grep pattern2. But what if I want to do something the result of which would be like grep -E 'pattern1.*pattern2[.*...]...' depending on how many patterns are supplied to the function at runtime i.e. mo1 pattern1 pattern2 [...] etc.? I can see the @ array could provide the number of items and I could construct over a loop a variable (finalpattern='$1.*$2.*$3') that would end up being the expression used for grep. But I can't think of how to abstract that bit where you craft the expression in the function? Or is there a better/simpler way to do something like this?










    share|improve this question
























      4












      4








      4


      1






      I have exported some MS Word documents to plain text and use this function to parse the contents of the .txt files in the current directory:



      mo1 () 
      for i in *.txt; do
      echo "File: $i"
      grep -n -HC 1 "$@" "$i"
      done



      If I had more than one pattern to look for, I could do mo1 | grep pattern2. But what if I want to do something the result of which would be like grep -E 'pattern1.*pattern2[.*...]...' depending on how many patterns are supplied to the function at runtime i.e. mo1 pattern1 pattern2 [...] etc.? I can see the @ array could provide the number of items and I could construct over a loop a variable (finalpattern='$1.*$2.*$3') that would end up being the expression used for grep. But I can't think of how to abstract that bit where you craft the expression in the function? Or is there a better/simpler way to do something like this?










      share|improve this question














      I have exported some MS Word documents to plain text and use this function to parse the contents of the .txt files in the current directory:



      mo1 () 
      for i in *.txt; do
      echo "File: $i"
      grep -n -HC 1 "$@" "$i"
      done



      If I had more than one pattern to look for, I could do mo1 | grep pattern2. But what if I want to do something the result of which would be like grep -E 'pattern1.*pattern2[.*...]...' depending on how many patterns are supplied to the function at runtime i.e. mo1 pattern1 pattern2 [...] etc.? I can see the @ array could provide the number of items and I could construct over a loop a variable (finalpattern='$1.*$2.*$3') that would end up being the expression used for grep. But I can't think of how to abstract that bit where you craft the expression in the function? Or is there a better/simpler way to do something like this?







      shell-script grep






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jul 17 '14 at 22:47









      jus cogens primejus cogens prime

      2,70693067




      2,70693067




















          2 Answers
          2






          active

          oldest

          votes


















          5





          +100









          You can leverage the printf builtin.



          mo1 () 
          for file in *.txt; do
          grep -n -C1 "$(printf "%s.*" "$@")" "$file"
          done



          This simple version inserts .* after the last element. It doesn't matter for this specific use case, but in other cases (e.g. grep -o) you may need to strip off the extra .* at the end.



          mo1 () 
          pattern=$(printf "%s.*" "$@")
          pattern=$pattern%??
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          In bash, you can put the printf output directly in a variable, which is slightly faster than using a command substitution (but this is unlikely to ever matter, even on Cygwin where subshells are slow).



          mo1 () 
          printf -v pattern "%s.*" "$@"
          pattern=$pattern%??
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          If you wanted to insert a single character between the positional parameters, you could set IFS to that character and use "$@". But that doesn't work if the separator is more than one character. In ksh and bash, if there's a character that doesn't appear in the pattern, you can use that for joining and then perform a replacement. For example, here, it wouldn't make sense for patterns to contain newlines, so:



          mo1 () 
          typeset IFS=$'n'
          typeset pattern="$*"
          pattern=$pattern//$'n'/.*
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          In zsh, of course, there's a direct way.



          mo1 () 
          for file in *.txt; do
          grep -n -C1 $(j:.*:)@ $file
          done






          share|improve this answer























          • Thank you for all the insight!! I think with the first one, I get some interaction because of C1, as if the output lines are context lines of the lines that contained the patterns, whereas they don't themselves contain it - at least I had that with the 3 terms I used for trying out the solutions. Otherwise this works flawlessly and will be very useful, thanks again!

            – jus cogens prime
            Jul 18 '14 at 3:30


















          0














          Alternatively, you can use the --file option to grep:



          -f FILE, --file=FILE
          Obtain patterns from FILE, one per line. The empty file contains
          zero patterns, and therefore matches nothing. (-f is specified by POSIX.)





          share|improve this answer























          • Thanks! The idea is interesting but when you create such a pattern file it's really doing OR i.e. it will find lines with either patterns from that pattern file...

            – jus cogens prime
            Jul 18 '14 at 9:52










          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',
          autoActivateHeartbeat: false,
          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%2f145196%2fhow-do-you-construct-a-grep-command-to-match-a-number-of-patterns-depending-on%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          2 Answers
          2






          active

          oldest

          votes








          2 Answers
          2






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          5





          +100









          You can leverage the printf builtin.



          mo1 () 
          for file in *.txt; do
          grep -n -C1 "$(printf "%s.*" "$@")" "$file"
          done



          This simple version inserts .* after the last element. It doesn't matter for this specific use case, but in other cases (e.g. grep -o) you may need to strip off the extra .* at the end.



          mo1 () 
          pattern=$(printf "%s.*" "$@")
          pattern=$pattern%??
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          In bash, you can put the printf output directly in a variable, which is slightly faster than using a command substitution (but this is unlikely to ever matter, even on Cygwin where subshells are slow).



          mo1 () 
          printf -v pattern "%s.*" "$@"
          pattern=$pattern%??
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          If you wanted to insert a single character between the positional parameters, you could set IFS to that character and use "$@". But that doesn't work if the separator is more than one character. In ksh and bash, if there's a character that doesn't appear in the pattern, you can use that for joining and then perform a replacement. For example, here, it wouldn't make sense for patterns to contain newlines, so:



          mo1 () 
          typeset IFS=$'n'
          typeset pattern="$*"
          pattern=$pattern//$'n'/.*
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          In zsh, of course, there's a direct way.



          mo1 () 
          for file in *.txt; do
          grep -n -C1 $(j:.*:)@ $file
          done






          share|improve this answer























          • Thank you for all the insight!! I think with the first one, I get some interaction because of C1, as if the output lines are context lines of the lines that contained the patterns, whereas they don't themselves contain it - at least I had that with the 3 terms I used for trying out the solutions. Otherwise this works flawlessly and will be very useful, thanks again!

            – jus cogens prime
            Jul 18 '14 at 3:30















          5





          +100









          You can leverage the printf builtin.



          mo1 () 
          for file in *.txt; do
          grep -n -C1 "$(printf "%s.*" "$@")" "$file"
          done



          This simple version inserts .* after the last element. It doesn't matter for this specific use case, but in other cases (e.g. grep -o) you may need to strip off the extra .* at the end.



          mo1 () 
          pattern=$(printf "%s.*" "$@")
          pattern=$pattern%??
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          In bash, you can put the printf output directly in a variable, which is slightly faster than using a command substitution (but this is unlikely to ever matter, even on Cygwin where subshells are slow).



          mo1 () 
          printf -v pattern "%s.*" "$@"
          pattern=$pattern%??
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          If you wanted to insert a single character between the positional parameters, you could set IFS to that character and use "$@". But that doesn't work if the separator is more than one character. In ksh and bash, if there's a character that doesn't appear in the pattern, you can use that for joining and then perform a replacement. For example, here, it wouldn't make sense for patterns to contain newlines, so:



          mo1 () 
          typeset IFS=$'n'
          typeset pattern="$*"
          pattern=$pattern//$'n'/.*
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          In zsh, of course, there's a direct way.



          mo1 () 
          for file in *.txt; do
          grep -n -C1 $(j:.*:)@ $file
          done






          share|improve this answer























          • Thank you for all the insight!! I think with the first one, I get some interaction because of C1, as if the output lines are context lines of the lines that contained the patterns, whereas they don't themselves contain it - at least I had that with the 3 terms I used for trying out the solutions. Otherwise this works flawlessly and will be very useful, thanks again!

            – jus cogens prime
            Jul 18 '14 at 3:30













          5





          +100







          5





          +100



          5




          +100





          You can leverage the printf builtin.



          mo1 () 
          for file in *.txt; do
          grep -n -C1 "$(printf "%s.*" "$@")" "$file"
          done



          This simple version inserts .* after the last element. It doesn't matter for this specific use case, but in other cases (e.g. grep -o) you may need to strip off the extra .* at the end.



          mo1 () 
          pattern=$(printf "%s.*" "$@")
          pattern=$pattern%??
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          In bash, you can put the printf output directly in a variable, which is slightly faster than using a command substitution (but this is unlikely to ever matter, even on Cygwin where subshells are slow).



          mo1 () 
          printf -v pattern "%s.*" "$@"
          pattern=$pattern%??
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          If you wanted to insert a single character between the positional parameters, you could set IFS to that character and use "$@". But that doesn't work if the separator is more than one character. In ksh and bash, if there's a character that doesn't appear in the pattern, you can use that for joining and then perform a replacement. For example, here, it wouldn't make sense for patterns to contain newlines, so:



          mo1 () 
          typeset IFS=$'n'
          typeset pattern="$*"
          pattern=$pattern//$'n'/.*
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          In zsh, of course, there's a direct way.



          mo1 () 
          for file in *.txt; do
          grep -n -C1 $(j:.*:)@ $file
          done






          share|improve this answer













          You can leverage the printf builtin.



          mo1 () 
          for file in *.txt; do
          grep -n -C1 "$(printf "%s.*" "$@")" "$file"
          done



          This simple version inserts .* after the last element. It doesn't matter for this specific use case, but in other cases (e.g. grep -o) you may need to strip off the extra .* at the end.



          mo1 () 
          pattern=$(printf "%s.*" "$@")
          pattern=$pattern%??
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          In bash, you can put the printf output directly in a variable, which is slightly faster than using a command substitution (but this is unlikely to ever matter, even on Cygwin where subshells are slow).



          mo1 () 
          printf -v pattern "%s.*" "$@"
          pattern=$pattern%??
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          If you wanted to insert a single character between the positional parameters, you could set IFS to that character and use "$@". But that doesn't work if the separator is more than one character. In ksh and bash, if there's a character that doesn't appear in the pattern, you can use that for joining and then perform a replacement. For example, here, it wouldn't make sense for patterns to contain newlines, so:



          mo1 () 
          typeset IFS=$'n'
          typeset pattern="$*"
          pattern=$pattern//$'n'/.*
          for file in *.txt; do
          grep -n -C1 "$pattern" "$file"
          done



          In zsh, of course, there's a direct way.



          mo1 () 
          for file in *.txt; do
          grep -n -C1 $(j:.*:)@ $file
          done







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jul 17 '14 at 23:06









          GillesGilles

          536k12810821600




          536k12810821600












          • Thank you for all the insight!! I think with the first one, I get some interaction because of C1, as if the output lines are context lines of the lines that contained the patterns, whereas they don't themselves contain it - at least I had that with the 3 terms I used for trying out the solutions. Otherwise this works flawlessly and will be very useful, thanks again!

            – jus cogens prime
            Jul 18 '14 at 3:30

















          • Thank you for all the insight!! I think with the first one, I get some interaction because of C1, as if the output lines are context lines of the lines that contained the patterns, whereas they don't themselves contain it - at least I had that with the 3 terms I used for trying out the solutions. Otherwise this works flawlessly and will be very useful, thanks again!

            – jus cogens prime
            Jul 18 '14 at 3:30
















          Thank you for all the insight!! I think with the first one, I get some interaction because of C1, as if the output lines are context lines of the lines that contained the patterns, whereas they don't themselves contain it - at least I had that with the 3 terms I used for trying out the solutions. Otherwise this works flawlessly and will be very useful, thanks again!

          – jus cogens prime
          Jul 18 '14 at 3:30





          Thank you for all the insight!! I think with the first one, I get some interaction because of C1, as if the output lines are context lines of the lines that contained the patterns, whereas they don't themselves contain it - at least I had that with the 3 terms I used for trying out the solutions. Otherwise this works flawlessly and will be very useful, thanks again!

          – jus cogens prime
          Jul 18 '14 at 3:30













          0














          Alternatively, you can use the --file option to grep:



          -f FILE, --file=FILE
          Obtain patterns from FILE, one per line. The empty file contains
          zero patterns, and therefore matches nothing. (-f is specified by POSIX.)





          share|improve this answer























          • Thanks! The idea is interesting but when you create such a pattern file it's really doing OR i.e. it will find lines with either patterns from that pattern file...

            – jus cogens prime
            Jul 18 '14 at 9:52















          0














          Alternatively, you can use the --file option to grep:



          -f FILE, --file=FILE
          Obtain patterns from FILE, one per line. The empty file contains
          zero patterns, and therefore matches nothing. (-f is specified by POSIX.)





          share|improve this answer























          • Thanks! The idea is interesting but when you create such a pattern file it's really doing OR i.e. it will find lines with either patterns from that pattern file...

            – jus cogens prime
            Jul 18 '14 at 9:52













          0












          0








          0







          Alternatively, you can use the --file option to grep:



          -f FILE, --file=FILE
          Obtain patterns from FILE, one per line. The empty file contains
          zero patterns, and therefore matches nothing. (-f is specified by POSIX.)





          share|improve this answer













          Alternatively, you can use the --file option to grep:



          -f FILE, --file=FILE
          Obtain patterns from FILE, one per line. The empty file contains
          zero patterns, and therefore matches nothing. (-f is specified by POSIX.)






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jul 18 '14 at 4:01









          Christian MannChristian Mann

          1013




          1013












          • Thanks! The idea is interesting but when you create such a pattern file it's really doing OR i.e. it will find lines with either patterns from that pattern file...

            – jus cogens prime
            Jul 18 '14 at 9:52

















          • Thanks! The idea is interesting but when you create such a pattern file it's really doing OR i.e. it will find lines with either patterns from that pattern file...

            – jus cogens prime
            Jul 18 '14 at 9:52
















          Thanks! The idea is interesting but when you create such a pattern file it's really doing OR i.e. it will find lines with either patterns from that pattern file...

          – jus cogens prime
          Jul 18 '14 at 9:52





          Thanks! The idea is interesting but when you create such a pattern file it's really doing OR i.e. it will find lines with either patterns from that pattern file...

          – jus cogens prime
          Jul 18 '14 at 9:52

















          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.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f145196%2fhow-do-you-construct-a-grep-command-to-match-a-number-of-patterns-depending-on%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






          Popular posts from this blog

          How to check contact read email or not when send email to Individual?

          Displaying single band from multi-band raster using QGIS

          How many registers does an x86_64 CPU actually have?