grepping a fixed string at the beginning of a line

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











up vote
17
down vote

favorite
1












grep "^$1" sort of works, but how do I escape "$1" so grep doesn't interpret any characters in it specially?



Or is there a better way?



Edit:
I don't want to search for '^$1' but for a dynamically inserted fixed string which should only be matched if it's at the beginning of a line. That's what I meant by the $1.










share|improve this question























  • Did you try to use single quotes instead of double quotes, e.g. grep '^$1'? Or didn't you mean that you want to prevent the $1being expanded by the shell?
    – mnille
    May 11 '16 at 8:50











  • @mnille I don't want to search for '^$1' but for a dynamically inserted fixed string which should only be matched if it's at the beginning of a line. That's what I meant by the $1.
    – PSkocik
    May 11 '16 at 8:53






  • 3




    You can do it with grep too but you'll have to escape any special character in your string first e.g. printf %s ^;printf %s "$1" | sed 's/[.*^$]/\&/g'; } | grep -f- infile
    – don_crissti
    May 11 '16 at 16:04











  • @don_crissti that's better than some of the other answers. Care to make it one?
    – roaima
    May 14 '16 at 7:36










  • @roaima - I know but there's already a bunch of answers here and this (escaping the special chars inside vars) is something I (and a couple of other users here) have been hammering home for quite some time... You could always add it to your answer if you wish and I'll remove the comment here (don't forget to add the missing the leading brace).
    – don_crissti
    May 14 '16 at 17:38














up vote
17
down vote

favorite
1












grep "^$1" sort of works, but how do I escape "$1" so grep doesn't interpret any characters in it specially?



Or is there a better way?



Edit:
I don't want to search for '^$1' but for a dynamically inserted fixed string which should only be matched if it's at the beginning of a line. That's what I meant by the $1.










share|improve this question























  • Did you try to use single quotes instead of double quotes, e.g. grep '^$1'? Or didn't you mean that you want to prevent the $1being expanded by the shell?
    – mnille
    May 11 '16 at 8:50











  • @mnille I don't want to search for '^$1' but for a dynamically inserted fixed string which should only be matched if it's at the beginning of a line. That's what I meant by the $1.
    – PSkocik
    May 11 '16 at 8:53






  • 3




    You can do it with grep too but you'll have to escape any special character in your string first e.g. printf %s ^;printf %s "$1" | sed 's/[.*^$]/\&/g'; } | grep -f- infile
    – don_crissti
    May 11 '16 at 16:04











  • @don_crissti that's better than some of the other answers. Care to make it one?
    – roaima
    May 14 '16 at 7:36










  • @roaima - I know but there's already a bunch of answers here and this (escaping the special chars inside vars) is something I (and a couple of other users here) have been hammering home for quite some time... You could always add it to your answer if you wish and I'll remove the comment here (don't forget to add the missing the leading brace).
    – don_crissti
    May 14 '16 at 17:38












up vote
17
down vote

favorite
1









up vote
17
down vote

favorite
1






1





grep "^$1" sort of works, but how do I escape "$1" so grep doesn't interpret any characters in it specially?



Or is there a better way?



Edit:
I don't want to search for '^$1' but for a dynamically inserted fixed string which should only be matched if it's at the beginning of a line. That's what I meant by the $1.










share|improve this question















grep "^$1" sort of works, but how do I escape "$1" so grep doesn't interpret any characters in it specially?



Or is there a better way?



Edit:
I don't want to search for '^$1' but for a dynamically inserted fixed string which should only be matched if it's at the beginning of a line. That's what I meant by the $1.







grep






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 11 '16 at 20:09

























asked May 11 '16 at 8:46









PSkocik

17.4k34893




17.4k34893











  • Did you try to use single quotes instead of double quotes, e.g. grep '^$1'? Or didn't you mean that you want to prevent the $1being expanded by the shell?
    – mnille
    May 11 '16 at 8:50











  • @mnille I don't want to search for '^$1' but for a dynamically inserted fixed string which should only be matched if it's at the beginning of a line. That's what I meant by the $1.
    – PSkocik
    May 11 '16 at 8:53






  • 3




    You can do it with grep too but you'll have to escape any special character in your string first e.g. printf %s ^;printf %s "$1" | sed 's/[.*^$]/\&/g'; } | grep -f- infile
    – don_crissti
    May 11 '16 at 16:04











  • @don_crissti that's better than some of the other answers. Care to make it one?
    – roaima
    May 14 '16 at 7:36










  • @roaima - I know but there's already a bunch of answers here and this (escaping the special chars inside vars) is something I (and a couple of other users here) have been hammering home for quite some time... You could always add it to your answer if you wish and I'll remove the comment here (don't forget to add the missing the leading brace).
    – don_crissti
    May 14 '16 at 17:38
















  • Did you try to use single quotes instead of double quotes, e.g. grep '^$1'? Or didn't you mean that you want to prevent the $1being expanded by the shell?
    – mnille
    May 11 '16 at 8:50











  • @mnille I don't want to search for '^$1' but for a dynamically inserted fixed string which should only be matched if it's at the beginning of a line. That's what I meant by the $1.
    – PSkocik
    May 11 '16 at 8:53






  • 3




    You can do it with grep too but you'll have to escape any special character in your string first e.g. printf %s ^;printf %s "$1" | sed 's/[.*^$]/\&/g'; } | grep -f- infile
    – don_crissti
    May 11 '16 at 16:04











  • @don_crissti that's better than some of the other answers. Care to make it one?
    – roaima
    May 14 '16 at 7:36










  • @roaima - I know but there's already a bunch of answers here and this (escaping the special chars inside vars) is something I (and a couple of other users here) have been hammering home for quite some time... You could always add it to your answer if you wish and I'll remove the comment here (don't forget to add the missing the leading brace).
    – don_crissti
    May 14 '16 at 17:38















Did you try to use single quotes instead of double quotes, e.g. grep '^$1'? Or didn't you mean that you want to prevent the $1being expanded by the shell?
– mnille
May 11 '16 at 8:50





Did you try to use single quotes instead of double quotes, e.g. grep '^$1'? Or didn't you mean that you want to prevent the $1being expanded by the shell?
– mnille
May 11 '16 at 8:50













@mnille I don't want to search for '^$1' but for a dynamically inserted fixed string which should only be matched if it's at the beginning of a line. That's what I meant by the $1.
– PSkocik
May 11 '16 at 8:53




@mnille I don't want to search for '^$1' but for a dynamically inserted fixed string which should only be matched if it's at the beginning of a line. That's what I meant by the $1.
– PSkocik
May 11 '16 at 8:53




3




3




You can do it with grep too but you'll have to escape any special character in your string first e.g. printf %s ^;printf %s "$1" | sed 's/[.*^$]/\&/g'; } | grep -f- infile
– don_crissti
May 11 '16 at 16:04





You can do it with grep too but you'll have to escape any special character in your string first e.g. printf %s ^;printf %s "$1" | sed 's/[.*^$]/\&/g'; } | grep -f- infile
– don_crissti
May 11 '16 at 16:04













@don_crissti that's better than some of the other answers. Care to make it one?
– roaima
May 14 '16 at 7:36




@don_crissti that's better than some of the other answers. Care to make it one?
– roaima
May 14 '16 at 7:36












@roaima - I know but there's already a bunch of answers here and this (escaping the special chars inside vars) is something I (and a couple of other users here) have been hammering home for quite some time... You could always add it to your answer if you wish and I'll remove the comment here (don't forget to add the missing the leading brace).
– don_crissti
May 14 '16 at 17:38




@roaima - I know but there's already a bunch of answers here and this (escaping the special chars inside vars) is something I (and a couple of other users here) have been hammering home for quite some time... You could always add it to your answer if you wish and I'll remove the comment here (don't forget to add the missing the leading brace).
– don_crissti
May 14 '16 at 17:38










8 Answers
8






active

oldest

votes

















up vote
7
down vote



accepted










I can't think of a way to do this using grep; ^ itself is part of a regular expression so using it requires regular expressions to be interpreted. It's trivial using substring matching in awk, perl or whatever:



awk -v search="$1" 'substr($0, 1, length(search)) == search print '


To handle search strings containing , you can use the same trick as in 123's answer:



search="$1" awk 'substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] print '





share|improve this answer






















  • This won't work for strings such as /
    – 123
    May 11 '16 at 9:18










  • @123 indeed, I've added a variant to handle that.
    – Stephen Kitt
    May 11 '16 at 9:24










  • Will still fail for complicated strings such as \///\\/ that is seen as \///\/ in the program. As far as i am aware there is no way to properly escape backslashes in awk, unless you know how many will be used beforehand.
    – 123
    May 11 '16 at 9:30







  • 1




    @123 thanks, I've adapted your trick of going through the environment to avoid escape processing.
    – Stephen Kitt
    May 11 '16 at 9:45










  • I still like this solution the best. Efficient (awk + no time wasted looking around), quick startup (awk + no additional processes needed to setup state) uses standard tools, and is quite concise. All the other answers lack at least some of these. (Efficiency is a strong point here as grep is known for unmatched speed.)
    – PSkocik
    May 12 '16 at 21:26

















up vote
12
down vote













If you only need to check whether or not a match is found, cut all input lines to the length of the desired prefix ($1) and then use fixed-pattern grep:



if cut -c 1-"$#1" | grep -qF "$1"; then
echo "found"
else
echo "not found"
fi


It's also easy to get the count of matching lines:



cut -c 1-"$#1" | grep -cF "$1"


Or the line numbers of all matching lines (line numbers start at 1):



cut -c 1-"$#1" | grep -nF "$1" | cut -d : -f 1


You could feed the line numbers to head and tail to get the full text of the matching lines, but at that point it's easier to just reach for a modern scripting language like Python or Ruby.



(The above examples assume Posix grep and cut. They assume the file to search comes from standard input, but can easily be adapted to take a filename instead.)



Edit: You should also ensure that the pattern ($1) is not a zero-length string. Otherwise cut fails saying values may not include zero. Also, if using Bash, use set -o pipefail to catch error-exits by cut.






share|improve this answer





























    up vote
    10
    down vote













    A way using perl which will respect backslashes



    v="$1" perl -ne 'print if index($_, $ENV"v" )==0' file


    This sets the environment variable v for the command, then prints if the index of the variable is 0 i.e the beginning of the line.



    You can also do identical in awk



    v="$1" awk 'index($0, ENVIRON["v"])==1' file





    share|improve this answer





























      up vote
      6
      down vote













      Here's an all-bash option, not that I recommend bash for text-processing, but it works.



      #!/usr/bin/env bash
      # searches for $1 at the beginning of the line of its input

      len=$#1
      while IFS= read -r line
      do
      [[ "$line:0:len" = "$1" ]] && printf "%sn" "$line"
      done


      The script computes the length len of the inputted parameter $1, then uses parameter expansion on each line to see if the first len characters match $1. If so, it prints the line.






      share|improve this answer



























        up vote
        3
        down vote













        As a filter:



        perl -ne 'BEGIN $pat = shift print if /^Q$pat/' search-pattern


        Run on one or more files:



        perl -ne 'BEGIN $pat = shift print if /^Q$pat/' search-pattern file..


        The “Quoting metacharacters” section of the perlre documentation explains:




        Quoting metacharacters



        Backslashed metacharacters in Perl are alphanumeric, such as b, w,
        n. Unlike some other regular expression languages, there are no
        backslashed symbols that aren’t alphanumeric. So anything that looks
        like \, (, ), [, ], , or is always interpreted as a literal
        character, not a metacharacter. This was once used in a common idiom
        to disable or quote the special meanings of regular expression
        metacharacters in a string that you want to use for a pattern. Simply
        quote all non-“word” characters:



         $pattern =~ s/(W)/\$1/g;


        (If use locale is set, then this depends on the current locale.) Today
        it is more common to use the quotemeta function or the Q
        metaquoting escape sequence to disable all metacharacters’ special
        meanings like this:



         /$unquotedQ$quotedE$unquoted/


        Beware that if you put literal backslashes (those not inside
        interpolated variables) between Q and E, double-quotish backslash
        interpolation may lead to confusing results. If you need to use
        literal backslashes within Q...E, consult “Gory details of parsing
        quoted constructs” in perlop.



        quotemeta and Q are fully described in quotemeta.







        share|improve this answer



























          up vote
          2
          down vote













          If there is a a character that you don't use, you could use that to mark the beginning of the line. For example, $'a' (ASCII 007). It's ugly but it will work:



           echo 'this is a line to match'; echo 'but this is not'; >file.txt

          stuffing=$'a' # Guaranteed never to appear in your source text
          required='this' # What we want to match that beginning of a line

          match=$(sed "s/^/$stuffing/" file.txt | grep -F "$stuffing$required" | sed "s/^$stuffing//")

          if [[ -n "$match" ]]
          then
          echo "Yay. We have a match: $match"
          fi


          If you don't need the matched line(s) then you can drop the trailing sed and use grep -qF. But it's much easier with awk (or perl)...






          share|improve this answer





























            up vote
            2
            down vote













            If your $1 is pure ASCII and your grep has the -P option (to enable PCRE), you can do this:





            #!/bin/bash

            line_start="$1"
            line_start_raw=$(printf '%s' "$line_start" | od -v -t x1 -An)
            line_start_hex=$(printf '\x%s' $line_start_raw)
            grep -P "^$line_start_hex"


            The idea here is that grep -P allows regular expressions with xXX to specify literal characters, where XX is the hex ASCII value of that character. The character is matched literally, even if it is otherwise a special regex character.



            od is used to convert the expected line start to a list of hex values, which are then strung together, each prefixed with x by printf. ^ is then prepended this string to build the required regex.




            If your $1 is unicode, then this becomes quite a bit harder, because there is not a 1:1 correspondence of characters to hex bytes as output by od.






            share|improve this answer





























              up vote
              0
              down vote













              When you want to look in a file without a loop you can use:

              Cut the file with the length of the search string



               cut -c1-$#1 < file


              Look for fixed strings and return line numbers



               grep -Fn "$1" <(cut -c1-$#1 < file)


              Use the line numbers for something like sed -n '3p;11p' file



               sed -n "$(grep -Fn "$1" <(cut -c1-$#1 < file) | sed 's/:.*/p;/' | tr -d 'n')" file


              When you want to delete these lines, use



               sed "$(grep -Fn "$1" <(cut -c1-$#1 < file) | sed 's/:.*/d;/' | tr -d 'n')" file




              share




















                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: false,
                showLowRepImageUploadWarning: true,
                reputationToPostImages: null,
                bindNavPrevention: true,
                postfix: "",
                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%2f282445%2fgrepping-a-fixed-string-at-the-beginning-of-a-line%23new-answer', 'question_page');

                );

                Post as a guest






























                8 Answers
                8






                active

                oldest

                votes








                8 Answers
                8






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes








                up vote
                7
                down vote



                accepted










                I can't think of a way to do this using grep; ^ itself is part of a regular expression so using it requires regular expressions to be interpreted. It's trivial using substring matching in awk, perl or whatever:



                awk -v search="$1" 'substr($0, 1, length(search)) == search print '


                To handle search strings containing , you can use the same trick as in 123's answer:



                search="$1" awk 'substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] print '





                share|improve this answer






















                • This won't work for strings such as /
                  – 123
                  May 11 '16 at 9:18










                • @123 indeed, I've added a variant to handle that.
                  – Stephen Kitt
                  May 11 '16 at 9:24










                • Will still fail for complicated strings such as \///\\/ that is seen as \///\/ in the program. As far as i am aware there is no way to properly escape backslashes in awk, unless you know how many will be used beforehand.
                  – 123
                  May 11 '16 at 9:30







                • 1




                  @123 thanks, I've adapted your trick of going through the environment to avoid escape processing.
                  – Stephen Kitt
                  May 11 '16 at 9:45










                • I still like this solution the best. Efficient (awk + no time wasted looking around), quick startup (awk + no additional processes needed to setup state) uses standard tools, and is quite concise. All the other answers lack at least some of these. (Efficiency is a strong point here as grep is known for unmatched speed.)
                  – PSkocik
                  May 12 '16 at 21:26














                up vote
                7
                down vote



                accepted










                I can't think of a way to do this using grep; ^ itself is part of a regular expression so using it requires regular expressions to be interpreted. It's trivial using substring matching in awk, perl or whatever:



                awk -v search="$1" 'substr($0, 1, length(search)) == search print '


                To handle search strings containing , you can use the same trick as in 123's answer:



                search="$1" awk 'substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] print '





                share|improve this answer






















                • This won't work for strings such as /
                  – 123
                  May 11 '16 at 9:18










                • @123 indeed, I've added a variant to handle that.
                  – Stephen Kitt
                  May 11 '16 at 9:24










                • Will still fail for complicated strings such as \///\\/ that is seen as \///\/ in the program. As far as i am aware there is no way to properly escape backslashes in awk, unless you know how many will be used beforehand.
                  – 123
                  May 11 '16 at 9:30







                • 1




                  @123 thanks, I've adapted your trick of going through the environment to avoid escape processing.
                  – Stephen Kitt
                  May 11 '16 at 9:45










                • I still like this solution the best. Efficient (awk + no time wasted looking around), quick startup (awk + no additional processes needed to setup state) uses standard tools, and is quite concise. All the other answers lack at least some of these. (Efficiency is a strong point here as grep is known for unmatched speed.)
                  – PSkocik
                  May 12 '16 at 21:26












                up vote
                7
                down vote



                accepted







                up vote
                7
                down vote



                accepted






                I can't think of a way to do this using grep; ^ itself is part of a regular expression so using it requires regular expressions to be interpreted. It's trivial using substring matching in awk, perl or whatever:



                awk -v search="$1" 'substr($0, 1, length(search)) == search print '


                To handle search strings containing , you can use the same trick as in 123's answer:



                search="$1" awk 'substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] print '





                share|improve this answer














                I can't think of a way to do this using grep; ^ itself is part of a regular expression so using it requires regular expressions to be interpreted. It's trivial using substring matching in awk, perl or whatever:



                awk -v search="$1" 'substr($0, 1, length(search)) == search print '


                To handle search strings containing , you can use the same trick as in 123's answer:



                search="$1" awk 'substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] print '






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Apr 13 '17 at 12:36









                Community♦

                1




                1










                answered May 11 '16 at 8:48









                Stephen Kitt

                152k23338406




                152k23338406











                • This won't work for strings such as /
                  – 123
                  May 11 '16 at 9:18










                • @123 indeed, I've added a variant to handle that.
                  – Stephen Kitt
                  May 11 '16 at 9:24










                • Will still fail for complicated strings such as \///\\/ that is seen as \///\/ in the program. As far as i am aware there is no way to properly escape backslashes in awk, unless you know how many will be used beforehand.
                  – 123
                  May 11 '16 at 9:30







                • 1




                  @123 thanks, I've adapted your trick of going through the environment to avoid escape processing.
                  – Stephen Kitt
                  May 11 '16 at 9:45










                • I still like this solution the best. Efficient (awk + no time wasted looking around), quick startup (awk + no additional processes needed to setup state) uses standard tools, and is quite concise. All the other answers lack at least some of these. (Efficiency is a strong point here as grep is known for unmatched speed.)
                  – PSkocik
                  May 12 '16 at 21:26
















                • This won't work for strings such as /
                  – 123
                  May 11 '16 at 9:18










                • @123 indeed, I've added a variant to handle that.
                  – Stephen Kitt
                  May 11 '16 at 9:24










                • Will still fail for complicated strings such as \///\\/ that is seen as \///\/ in the program. As far as i am aware there is no way to properly escape backslashes in awk, unless you know how many will be used beforehand.
                  – 123
                  May 11 '16 at 9:30







                • 1




                  @123 thanks, I've adapted your trick of going through the environment to avoid escape processing.
                  – Stephen Kitt
                  May 11 '16 at 9:45










                • I still like this solution the best. Efficient (awk + no time wasted looking around), quick startup (awk + no additional processes needed to setup state) uses standard tools, and is quite concise. All the other answers lack at least some of these. (Efficiency is a strong point here as grep is known for unmatched speed.)
                  – PSkocik
                  May 12 '16 at 21:26















                This won't work for strings such as /
                – 123
                May 11 '16 at 9:18




                This won't work for strings such as /
                – 123
                May 11 '16 at 9:18












                @123 indeed, I've added a variant to handle that.
                – Stephen Kitt
                May 11 '16 at 9:24




                @123 indeed, I've added a variant to handle that.
                – Stephen Kitt
                May 11 '16 at 9:24












                Will still fail for complicated strings such as \///\\/ that is seen as \///\/ in the program. As far as i am aware there is no way to properly escape backslashes in awk, unless you know how many will be used beforehand.
                – 123
                May 11 '16 at 9:30





                Will still fail for complicated strings such as \///\\/ that is seen as \///\/ in the program. As far as i am aware there is no way to properly escape backslashes in awk, unless you know how many will be used beforehand.
                – 123
                May 11 '16 at 9:30





                1




                1




                @123 thanks, I've adapted your trick of going through the environment to avoid escape processing.
                – Stephen Kitt
                May 11 '16 at 9:45




                @123 thanks, I've adapted your trick of going through the environment to avoid escape processing.
                – Stephen Kitt
                May 11 '16 at 9:45












                I still like this solution the best. Efficient (awk + no time wasted looking around), quick startup (awk + no additional processes needed to setup state) uses standard tools, and is quite concise. All the other answers lack at least some of these. (Efficiency is a strong point here as grep is known for unmatched speed.)
                – PSkocik
                May 12 '16 at 21:26




                I still like this solution the best. Efficient (awk + no time wasted looking around), quick startup (awk + no additional processes needed to setup state) uses standard tools, and is quite concise. All the other answers lack at least some of these. (Efficiency is a strong point here as grep is known for unmatched speed.)
                – PSkocik
                May 12 '16 at 21:26












                up vote
                12
                down vote













                If you only need to check whether or not a match is found, cut all input lines to the length of the desired prefix ($1) and then use fixed-pattern grep:



                if cut -c 1-"$#1" | grep -qF "$1"; then
                echo "found"
                else
                echo "not found"
                fi


                It's also easy to get the count of matching lines:



                cut -c 1-"$#1" | grep -cF "$1"


                Or the line numbers of all matching lines (line numbers start at 1):



                cut -c 1-"$#1" | grep -nF "$1" | cut -d : -f 1


                You could feed the line numbers to head and tail to get the full text of the matching lines, but at that point it's easier to just reach for a modern scripting language like Python or Ruby.



                (The above examples assume Posix grep and cut. They assume the file to search comes from standard input, but can easily be adapted to take a filename instead.)



                Edit: You should also ensure that the pattern ($1) is not a zero-length string. Otherwise cut fails saying values may not include zero. Also, if using Bash, use set -o pipefail to catch error-exits by cut.






                share|improve this answer


























                  up vote
                  12
                  down vote













                  If you only need to check whether or not a match is found, cut all input lines to the length of the desired prefix ($1) and then use fixed-pattern grep:



                  if cut -c 1-"$#1" | grep -qF "$1"; then
                  echo "found"
                  else
                  echo "not found"
                  fi


                  It's also easy to get the count of matching lines:



                  cut -c 1-"$#1" | grep -cF "$1"


                  Or the line numbers of all matching lines (line numbers start at 1):



                  cut -c 1-"$#1" | grep -nF "$1" | cut -d : -f 1


                  You could feed the line numbers to head and tail to get the full text of the matching lines, but at that point it's easier to just reach for a modern scripting language like Python or Ruby.



                  (The above examples assume Posix grep and cut. They assume the file to search comes from standard input, but can easily be adapted to take a filename instead.)



                  Edit: You should also ensure that the pattern ($1) is not a zero-length string. Otherwise cut fails saying values may not include zero. Also, if using Bash, use set -o pipefail to catch error-exits by cut.






                  share|improve this answer
























                    up vote
                    12
                    down vote










                    up vote
                    12
                    down vote









                    If you only need to check whether or not a match is found, cut all input lines to the length of the desired prefix ($1) and then use fixed-pattern grep:



                    if cut -c 1-"$#1" | grep -qF "$1"; then
                    echo "found"
                    else
                    echo "not found"
                    fi


                    It's also easy to get the count of matching lines:



                    cut -c 1-"$#1" | grep -cF "$1"


                    Or the line numbers of all matching lines (line numbers start at 1):



                    cut -c 1-"$#1" | grep -nF "$1" | cut -d : -f 1


                    You could feed the line numbers to head and tail to get the full text of the matching lines, but at that point it's easier to just reach for a modern scripting language like Python or Ruby.



                    (The above examples assume Posix grep and cut. They assume the file to search comes from standard input, but can easily be adapted to take a filename instead.)



                    Edit: You should also ensure that the pattern ($1) is not a zero-length string. Otherwise cut fails saying values may not include zero. Also, if using Bash, use set -o pipefail to catch error-exits by cut.






                    share|improve this answer














                    If you only need to check whether or not a match is found, cut all input lines to the length of the desired prefix ($1) and then use fixed-pattern grep:



                    if cut -c 1-"$#1" | grep -qF "$1"; then
                    echo "found"
                    else
                    echo "not found"
                    fi


                    It's also easy to get the count of matching lines:



                    cut -c 1-"$#1" | grep -cF "$1"


                    Or the line numbers of all matching lines (line numbers start at 1):



                    cut -c 1-"$#1" | grep -nF "$1" | cut -d : -f 1


                    You could feed the line numbers to head and tail to get the full text of the matching lines, but at that point it's easier to just reach for a modern scripting language like Python or Ruby.



                    (The above examples assume Posix grep and cut. They assume the file to search comes from standard input, but can easily be adapted to take a filename instead.)



                    Edit: You should also ensure that the pattern ($1) is not a zero-length string. Otherwise cut fails saying values may not include zero. Also, if using Bash, use set -o pipefail to catch error-exits by cut.







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited May 11 '16 at 15:40

























                    answered May 11 '16 at 15:32









                    Lassi

                    23817




                    23817




















                        up vote
                        10
                        down vote













                        A way using perl which will respect backslashes



                        v="$1" perl -ne 'print if index($_, $ENV"v" )==0' file


                        This sets the environment variable v for the command, then prints if the index of the variable is 0 i.e the beginning of the line.



                        You can also do identical in awk



                        v="$1" awk 'index($0, ENVIRON["v"])==1' file





                        share|improve this answer


























                          up vote
                          10
                          down vote













                          A way using perl which will respect backslashes



                          v="$1" perl -ne 'print if index($_, $ENV"v" )==0' file


                          This sets the environment variable v for the command, then prints if the index of the variable is 0 i.e the beginning of the line.



                          You can also do identical in awk



                          v="$1" awk 'index($0, ENVIRON["v"])==1' file





                          share|improve this answer
























                            up vote
                            10
                            down vote










                            up vote
                            10
                            down vote









                            A way using perl which will respect backslashes



                            v="$1" perl -ne 'print if index($_, $ENV"v" )==0' file


                            This sets the environment variable v for the command, then prints if the index of the variable is 0 i.e the beginning of the line.



                            You can also do identical in awk



                            v="$1" awk 'index($0, ENVIRON["v"])==1' file





                            share|improve this answer














                            A way using perl which will respect backslashes



                            v="$1" perl -ne 'print if index($_, $ENV"v" )==0' file


                            This sets the environment variable v for the command, then prints if the index of the variable is 0 i.e the beginning of the line.



                            You can also do identical in awk



                            v="$1" awk 'index($0, ENVIRON["v"])==1' file






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited May 11 '16 at 10:00

























                            answered May 11 '16 at 9:26









                            123

                            1,48738




                            1,48738




















                                up vote
                                6
                                down vote













                                Here's an all-bash option, not that I recommend bash for text-processing, but it works.



                                #!/usr/bin/env bash
                                # searches for $1 at the beginning of the line of its input

                                len=$#1
                                while IFS= read -r line
                                do
                                [[ "$line:0:len" = "$1" ]] && printf "%sn" "$line"
                                done


                                The script computes the length len of the inputted parameter $1, then uses parameter expansion on each line to see if the first len characters match $1. If so, it prints the line.






                                share|improve this answer
























                                  up vote
                                  6
                                  down vote













                                  Here's an all-bash option, not that I recommend bash for text-processing, but it works.



                                  #!/usr/bin/env bash
                                  # searches for $1 at the beginning of the line of its input

                                  len=$#1
                                  while IFS= read -r line
                                  do
                                  [[ "$line:0:len" = "$1" ]] && printf "%sn" "$line"
                                  done


                                  The script computes the length len of the inputted parameter $1, then uses parameter expansion on each line to see if the first len characters match $1. If so, it prints the line.






                                  share|improve this answer






















                                    up vote
                                    6
                                    down vote










                                    up vote
                                    6
                                    down vote









                                    Here's an all-bash option, not that I recommend bash for text-processing, but it works.



                                    #!/usr/bin/env bash
                                    # searches for $1 at the beginning of the line of its input

                                    len=$#1
                                    while IFS= read -r line
                                    do
                                    [[ "$line:0:len" = "$1" ]] && printf "%sn" "$line"
                                    done


                                    The script computes the length len of the inputted parameter $1, then uses parameter expansion on each line to see if the first len characters match $1. If so, it prints the line.






                                    share|improve this answer












                                    Here's an all-bash option, not that I recommend bash for text-processing, but it works.



                                    #!/usr/bin/env bash
                                    # searches for $1 at the beginning of the line of its input

                                    len=$#1
                                    while IFS= read -r line
                                    do
                                    [[ "$line:0:len" = "$1" ]] && printf "%sn" "$line"
                                    done


                                    The script computes the length len of the inputted parameter $1, then uses parameter expansion on each line to see if the first len characters match $1. If so, it prints the line.







                                    share|improve this answer












                                    share|improve this answer



                                    share|improve this answer










                                    answered May 11 '16 at 11:16









                                    Jeff Schaller

                                    34.5k951115




                                    34.5k951115




















                                        up vote
                                        3
                                        down vote













                                        As a filter:



                                        perl -ne 'BEGIN $pat = shift print if /^Q$pat/' search-pattern


                                        Run on one or more files:



                                        perl -ne 'BEGIN $pat = shift print if /^Q$pat/' search-pattern file..


                                        The “Quoting metacharacters” section of the perlre documentation explains:




                                        Quoting metacharacters



                                        Backslashed metacharacters in Perl are alphanumeric, such as b, w,
                                        n. Unlike some other regular expression languages, there are no
                                        backslashed symbols that aren’t alphanumeric. So anything that looks
                                        like \, (, ), [, ], , or is always interpreted as a literal
                                        character, not a metacharacter. This was once used in a common idiom
                                        to disable or quote the special meanings of regular expression
                                        metacharacters in a string that you want to use for a pattern. Simply
                                        quote all non-“word” characters:



                                         $pattern =~ s/(W)/\$1/g;


                                        (If use locale is set, then this depends on the current locale.) Today
                                        it is more common to use the quotemeta function or the Q
                                        metaquoting escape sequence to disable all metacharacters’ special
                                        meanings like this:



                                         /$unquotedQ$quotedE$unquoted/


                                        Beware that if you put literal backslashes (those not inside
                                        interpolated variables) between Q and E, double-quotish backslash
                                        interpolation may lead to confusing results. If you need to use
                                        literal backslashes within Q...E, consult “Gory details of parsing
                                        quoted constructs” in perlop.



                                        quotemeta and Q are fully described in quotemeta.







                                        share|improve this answer
























                                          up vote
                                          3
                                          down vote













                                          As a filter:



                                          perl -ne 'BEGIN $pat = shift print if /^Q$pat/' search-pattern


                                          Run on one or more files:



                                          perl -ne 'BEGIN $pat = shift print if /^Q$pat/' search-pattern file..


                                          The “Quoting metacharacters” section of the perlre documentation explains:




                                          Quoting metacharacters



                                          Backslashed metacharacters in Perl are alphanumeric, such as b, w,
                                          n. Unlike some other regular expression languages, there are no
                                          backslashed symbols that aren’t alphanumeric. So anything that looks
                                          like \, (, ), [, ], , or is always interpreted as a literal
                                          character, not a metacharacter. This was once used in a common idiom
                                          to disable or quote the special meanings of regular expression
                                          metacharacters in a string that you want to use for a pattern. Simply
                                          quote all non-“word” characters:



                                           $pattern =~ s/(W)/\$1/g;


                                          (If use locale is set, then this depends on the current locale.) Today
                                          it is more common to use the quotemeta function or the Q
                                          metaquoting escape sequence to disable all metacharacters’ special
                                          meanings like this:



                                           /$unquotedQ$quotedE$unquoted/


                                          Beware that if you put literal backslashes (those not inside
                                          interpolated variables) between Q and E, double-quotish backslash
                                          interpolation may lead to confusing results. If you need to use
                                          literal backslashes within Q...E, consult “Gory details of parsing
                                          quoted constructs” in perlop.



                                          quotemeta and Q are fully described in quotemeta.







                                          share|improve this answer






















                                            up vote
                                            3
                                            down vote










                                            up vote
                                            3
                                            down vote









                                            As a filter:



                                            perl -ne 'BEGIN $pat = shift print if /^Q$pat/' search-pattern


                                            Run on one or more files:



                                            perl -ne 'BEGIN $pat = shift print if /^Q$pat/' search-pattern file..


                                            The “Quoting metacharacters” section of the perlre documentation explains:




                                            Quoting metacharacters



                                            Backslashed metacharacters in Perl are alphanumeric, such as b, w,
                                            n. Unlike some other regular expression languages, there are no
                                            backslashed symbols that aren’t alphanumeric. So anything that looks
                                            like \, (, ), [, ], , or is always interpreted as a literal
                                            character, not a metacharacter. This was once used in a common idiom
                                            to disable or quote the special meanings of regular expression
                                            metacharacters in a string that you want to use for a pattern. Simply
                                            quote all non-“word” characters:



                                             $pattern =~ s/(W)/\$1/g;


                                            (If use locale is set, then this depends on the current locale.) Today
                                            it is more common to use the quotemeta function or the Q
                                            metaquoting escape sequence to disable all metacharacters’ special
                                            meanings like this:



                                             /$unquotedQ$quotedE$unquoted/


                                            Beware that if you put literal backslashes (those not inside
                                            interpolated variables) between Q and E, double-quotish backslash
                                            interpolation may lead to confusing results. If you need to use
                                            literal backslashes within Q...E, consult “Gory details of parsing
                                            quoted constructs” in perlop.



                                            quotemeta and Q are fully described in quotemeta.







                                            share|improve this answer












                                            As a filter:



                                            perl -ne 'BEGIN $pat = shift print if /^Q$pat/' search-pattern


                                            Run on one or more files:



                                            perl -ne 'BEGIN $pat = shift print if /^Q$pat/' search-pattern file..


                                            The “Quoting metacharacters” section of the perlre documentation explains:




                                            Quoting metacharacters



                                            Backslashed metacharacters in Perl are alphanumeric, such as b, w,
                                            n. Unlike some other regular expression languages, there are no
                                            backslashed symbols that aren’t alphanumeric. So anything that looks
                                            like \, (, ), [, ], , or is always interpreted as a literal
                                            character, not a metacharacter. This was once used in a common idiom
                                            to disable or quote the special meanings of regular expression
                                            metacharacters in a string that you want to use for a pattern. Simply
                                            quote all non-“word” characters:



                                             $pattern =~ s/(W)/\$1/g;


                                            (If use locale is set, then this depends on the current locale.) Today
                                            it is more common to use the quotemeta function or the Q
                                            metaquoting escape sequence to disable all metacharacters’ special
                                            meanings like this:



                                             /$unquotedQ$quotedE$unquoted/


                                            Beware that if you put literal backslashes (those not inside
                                            interpolated variables) between Q and E, double-quotish backslash
                                            interpolation may lead to confusing results. If you need to use
                                            literal backslashes within Q...E, consult “Gory details of parsing
                                            quoted constructs” in perlop.



                                            quotemeta and Q are fully described in quotemeta.








                                            share|improve this answer












                                            share|improve this answer



                                            share|improve this answer










                                            answered May 11 '16 at 18:29









                                            Greg Bacon

                                            1413




                                            1413




















                                                up vote
                                                2
                                                down vote













                                                If there is a a character that you don't use, you could use that to mark the beginning of the line. For example, $'a' (ASCII 007). It's ugly but it will work:



                                                 echo 'this is a line to match'; echo 'but this is not'; >file.txt

                                                stuffing=$'a' # Guaranteed never to appear in your source text
                                                required='this' # What we want to match that beginning of a line

                                                match=$(sed "s/^/$stuffing/" file.txt | grep -F "$stuffing$required" | sed "s/^$stuffing//")

                                                if [[ -n "$match" ]]
                                                then
                                                echo "Yay. We have a match: $match"
                                                fi


                                                If you don't need the matched line(s) then you can drop the trailing sed and use grep -qF. But it's much easier with awk (or perl)...






                                                share|improve this answer


























                                                  up vote
                                                  2
                                                  down vote













                                                  If there is a a character that you don't use, you could use that to mark the beginning of the line. For example, $'a' (ASCII 007). It's ugly but it will work:



                                                   echo 'this is a line to match'; echo 'but this is not'; >file.txt

                                                  stuffing=$'a' # Guaranteed never to appear in your source text
                                                  required='this' # What we want to match that beginning of a line

                                                  match=$(sed "s/^/$stuffing/" file.txt | grep -F "$stuffing$required" | sed "s/^$stuffing//")

                                                  if [[ -n "$match" ]]
                                                  then
                                                  echo "Yay. We have a match: $match"
                                                  fi


                                                  If you don't need the matched line(s) then you can drop the trailing sed and use grep -qF. But it's much easier with awk (or perl)...






                                                  share|improve this answer
























                                                    up vote
                                                    2
                                                    down vote










                                                    up vote
                                                    2
                                                    down vote









                                                    If there is a a character that you don't use, you could use that to mark the beginning of the line. For example, $'a' (ASCII 007). It's ugly but it will work:



                                                     echo 'this is a line to match'; echo 'but this is not'; >file.txt

                                                    stuffing=$'a' # Guaranteed never to appear in your source text
                                                    required='this' # What we want to match that beginning of a line

                                                    match=$(sed "s/^/$stuffing/" file.txt | grep -F "$stuffing$required" | sed "s/^$stuffing//")

                                                    if [[ -n "$match" ]]
                                                    then
                                                    echo "Yay. We have a match: $match"
                                                    fi


                                                    If you don't need the matched line(s) then you can drop the trailing sed and use grep -qF. But it's much easier with awk (or perl)...






                                                    share|improve this answer














                                                    If there is a a character that you don't use, you could use that to mark the beginning of the line. For example, $'a' (ASCII 007). It's ugly but it will work:



                                                     echo 'this is a line to match'; echo 'but this is not'; >file.txt

                                                    stuffing=$'a' # Guaranteed never to appear in your source text
                                                    required='this' # What we want to match that beginning of a line

                                                    match=$(sed "s/^/$stuffing/" file.txt | grep -F "$stuffing$required" | sed "s/^$stuffing//")

                                                    if [[ -n "$match" ]]
                                                    then
                                                    echo "Yay. We have a match: $match"
                                                    fi


                                                    If you don't need the matched line(s) then you can drop the trailing sed and use grep -qF. But it's much easier with awk (or perl)...







                                                    share|improve this answer














                                                    share|improve this answer



                                                    share|improve this answer








                                                    edited May 11 '16 at 21:21

























                                                    answered May 11 '16 at 9:07









                                                    roaima

                                                    41.3k547112




                                                    41.3k547112




















                                                        up vote
                                                        2
                                                        down vote













                                                        If your $1 is pure ASCII and your grep has the -P option (to enable PCRE), you can do this:





                                                        #!/bin/bash

                                                        line_start="$1"
                                                        line_start_raw=$(printf '%s' "$line_start" | od -v -t x1 -An)
                                                        line_start_hex=$(printf '\x%s' $line_start_raw)
                                                        grep -P "^$line_start_hex"


                                                        The idea here is that grep -P allows regular expressions with xXX to specify literal characters, where XX is the hex ASCII value of that character. The character is matched literally, even if it is otherwise a special regex character.



                                                        od is used to convert the expected line start to a list of hex values, which are then strung together, each prefixed with x by printf. ^ is then prepended this string to build the required regex.




                                                        If your $1 is unicode, then this becomes quite a bit harder, because there is not a 1:1 correspondence of characters to hex bytes as output by od.






                                                        share|improve this answer


























                                                          up vote
                                                          2
                                                          down vote













                                                          If your $1 is pure ASCII and your grep has the -P option (to enable PCRE), you can do this:





                                                          #!/bin/bash

                                                          line_start="$1"
                                                          line_start_raw=$(printf '%s' "$line_start" | od -v -t x1 -An)
                                                          line_start_hex=$(printf '\x%s' $line_start_raw)
                                                          grep -P "^$line_start_hex"


                                                          The idea here is that grep -P allows regular expressions with xXX to specify literal characters, where XX is the hex ASCII value of that character. The character is matched literally, even if it is otherwise a special regex character.



                                                          od is used to convert the expected line start to a list of hex values, which are then strung together, each prefixed with x by printf. ^ is then prepended this string to build the required regex.




                                                          If your $1 is unicode, then this becomes quite a bit harder, because there is not a 1:1 correspondence of characters to hex bytes as output by od.






                                                          share|improve this answer
























                                                            up vote
                                                            2
                                                            down vote










                                                            up vote
                                                            2
                                                            down vote









                                                            If your $1 is pure ASCII and your grep has the -P option (to enable PCRE), you can do this:





                                                            #!/bin/bash

                                                            line_start="$1"
                                                            line_start_raw=$(printf '%s' "$line_start" | od -v -t x1 -An)
                                                            line_start_hex=$(printf '\x%s' $line_start_raw)
                                                            grep -P "^$line_start_hex"


                                                            The idea here is that grep -P allows regular expressions with xXX to specify literal characters, where XX is the hex ASCII value of that character. The character is matched literally, even if it is otherwise a special regex character.



                                                            od is used to convert the expected line start to a list of hex values, which are then strung together, each prefixed with x by printf. ^ is then prepended this string to build the required regex.




                                                            If your $1 is unicode, then this becomes quite a bit harder, because there is not a 1:1 correspondence of characters to hex bytes as output by od.






                                                            share|improve this answer














                                                            If your $1 is pure ASCII and your grep has the -P option (to enable PCRE), you can do this:





                                                            #!/bin/bash

                                                            line_start="$1"
                                                            line_start_raw=$(printf '%s' "$line_start" | od -v -t x1 -An)
                                                            line_start_hex=$(printf '\x%s' $line_start_raw)
                                                            grep -P "^$line_start_hex"


                                                            The idea here is that grep -P allows regular expressions with xXX to specify literal characters, where XX is the hex ASCII value of that character. The character is matched literally, even if it is otherwise a special regex character.



                                                            od is used to convert the expected line start to a list of hex values, which are then strung together, each prefixed with x by printf. ^ is then prepended this string to build the required regex.




                                                            If your $1 is unicode, then this becomes quite a bit harder, because there is not a 1:1 correspondence of characters to hex bytes as output by od.







                                                            share|improve this answer














                                                            share|improve this answer



                                                            share|improve this answer








                                                            edited May 11 '16 at 21:41

























                                                            answered May 11 '16 at 21:36









                                                            Digital Trauma

                                                            5,67211528




                                                            5,67211528




















                                                                up vote
                                                                0
                                                                down vote













                                                                When you want to look in a file without a loop you can use:

                                                                Cut the file with the length of the search string



                                                                 cut -c1-$#1 < file


                                                                Look for fixed strings and return line numbers



                                                                 grep -Fn "$1" <(cut -c1-$#1 < file)


                                                                Use the line numbers for something like sed -n '3p;11p' file



                                                                 sed -n "$(grep -Fn "$1" <(cut -c1-$#1 < file) | sed 's/:.*/p;/' | tr -d 'n')" file


                                                                When you want to delete these lines, use



                                                                 sed "$(grep -Fn "$1" <(cut -c1-$#1 < file) | sed 's/:.*/d;/' | tr -d 'n')" file




                                                                share
























                                                                  up vote
                                                                  0
                                                                  down vote













                                                                  When you want to look in a file without a loop you can use:

                                                                  Cut the file with the length of the search string



                                                                   cut -c1-$#1 < file


                                                                  Look for fixed strings and return line numbers



                                                                   grep -Fn "$1" <(cut -c1-$#1 < file)


                                                                  Use the line numbers for something like sed -n '3p;11p' file



                                                                   sed -n "$(grep -Fn "$1" <(cut -c1-$#1 < file) | sed 's/:.*/p;/' | tr -d 'n')" file


                                                                  When you want to delete these lines, use



                                                                   sed "$(grep -Fn "$1" <(cut -c1-$#1 < file) | sed 's/:.*/d;/' | tr -d 'n')" file




                                                                  share






















                                                                    up vote
                                                                    0
                                                                    down vote










                                                                    up vote
                                                                    0
                                                                    down vote









                                                                    When you want to look in a file without a loop you can use:

                                                                    Cut the file with the length of the search string



                                                                     cut -c1-$#1 < file


                                                                    Look for fixed strings and return line numbers



                                                                     grep -Fn "$1" <(cut -c1-$#1 < file)


                                                                    Use the line numbers for something like sed -n '3p;11p' file



                                                                     sed -n "$(grep -Fn "$1" <(cut -c1-$#1 < file) | sed 's/:.*/p;/' | tr -d 'n')" file


                                                                    When you want to delete these lines, use



                                                                     sed "$(grep -Fn "$1" <(cut -c1-$#1 < file) | sed 's/:.*/d;/' | tr -d 'n')" file




                                                                    share












                                                                    When you want to look in a file without a loop you can use:

                                                                    Cut the file with the length of the search string



                                                                     cut -c1-$#1 < file


                                                                    Look for fixed strings and return line numbers



                                                                     grep -Fn "$1" <(cut -c1-$#1 < file)


                                                                    Use the line numbers for something like sed -n '3p;11p' file



                                                                     sed -n "$(grep -Fn "$1" <(cut -c1-$#1 < file) | sed 's/:.*/p;/' | tr -d 'n')" file


                                                                    When you want to delete these lines, use



                                                                     sed "$(grep -Fn "$1" <(cut -c1-$#1 < file) | sed 's/:.*/d;/' | tr -d 'n')" file





                                                                    share











                                                                    share


                                                                    share










                                                                    answered 1 min ago









                                                                    Walter A

                                                                    49429




                                                                    49429



























                                                                         

                                                                        draft saved


                                                                        draft discarded















































                                                                         


                                                                        draft saved


                                                                        draft discarded














                                                                        StackExchange.ready(
                                                                        function ()
                                                                        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f282445%2fgrepping-a-fixed-string-at-the-beginning-of-a-line%23new-answer', 'question_page');

                                                                        );

                                                                        Post as a guest













































































                                                                        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?