grepping a fixed string at the beginning of a line
Clash Royale CLAN TAG#URR8PPP
up vote
17
down vote
favorite
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
add a comment |Â
up vote
17
down vote
favorite
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
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$1
being 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 withgrep
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
add a comment |Â
up vote
17
down vote
favorite
up vote
17
down vote
favorite
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
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
grep
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$1
being 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 withgrep
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
add a comment |Â
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$1
being 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 withgrep
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 $1
being 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 $1
being 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
add a comment |Â
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 '
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
 |Â
show 1 more comment
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
.
add a comment |Â
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
add a comment |Â
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.
add a comment |Â
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 thequotemeta
function or theQ
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) betweenQ
andE
, double-quotish backslash
interpolation may lead to confusing results. If you need to use
literal backslashes withinQ...E
, consult âÂÂGory details of parsing
quoted constructsâ in perlop.
quotemeta
andQ
are fully described in quotemeta.
add a comment |Â
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
)...
add a comment |Â
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
.
add a comment |Â
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
add a comment |Â
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 '
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
 |Â
show 1 more comment
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 '
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
 |Â
show 1 more comment
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 '
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 '
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
 |Â
show 1 more comment
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
 |Â
show 1 more comment
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
.
add a comment |Â
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
.
add a comment |Â
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
.
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
.
edited May 11 '16 at 15:40
answered May 11 '16 at 15:32
Lassi
23817
23817
add a comment |Â
add a comment |Â
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
add a comment |Â
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
add a comment |Â
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
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
edited May 11 '16 at 10:00
answered May 11 '16 at 9:26
123
1,48738
1,48738
add a comment |Â
add a comment |Â
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.
add a comment |Â
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.
add a comment |Â
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.
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.
answered May 11 '16 at 11:16
Jeff Schaller
34.5k951115
34.5k951115
add a comment |Â
add a comment |Â
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 thequotemeta
function or theQ
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) betweenQ
andE
, double-quotish backslash
interpolation may lead to confusing results. If you need to use
literal backslashes withinQ...E
, consult âÂÂGory details of parsing
quoted constructsâ in perlop.
quotemeta
andQ
are fully described in quotemeta.
add a comment |Â
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 thequotemeta
function or theQ
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) betweenQ
andE
, double-quotish backslash
interpolation may lead to confusing results. If you need to use
literal backslashes withinQ...E
, consult âÂÂGory details of parsing
quoted constructsâ in perlop.
quotemeta
andQ
are fully described in quotemeta.
add a comment |Â
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 thequotemeta
function or theQ
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) betweenQ
andE
, double-quotish backslash
interpolation may lead to confusing results. If you need to use
literal backslashes withinQ...E
, consult âÂÂGory details of parsing
quoted constructsâ in perlop.
quotemeta
andQ
are fully described in quotemeta.
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 thequotemeta
function or theQ
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) betweenQ
andE
, double-quotish backslash
interpolation may lead to confusing results. If you need to use
literal backslashes withinQ...E
, consult âÂÂGory details of parsing
quoted constructsâ in perlop.
quotemeta
andQ
are fully described in quotemeta.
answered May 11 '16 at 18:29
Greg Bacon
1413
1413
add a comment |Â
add a comment |Â
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
)...
add a comment |Â
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
)...
add a comment |Â
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
)...
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
)...
edited May 11 '16 at 21:21
answered May 11 '16 at 9:07
roaima
41.3k547112
41.3k547112
add a comment |Â
add a comment |Â
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
.
add a comment |Â
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
.
add a comment |Â
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
.
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
.
edited May 11 '16 at 21:41
answered May 11 '16 at 21:36
Digital Trauma
5,67211528
5,67211528
add a comment |Â
add a comment |Â
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
add a comment |Â
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
add a comment |Â
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
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
answered 1 min ago
Walter A
49429
49429
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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$1
being 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