在行首grepping一个固定的字符串


20

grep "^$1"这类作品,但是我该如何逃脱,"$1"以便grep不会特别解释其中的任何字符?

或者,还有更好的方法?

编辑: 我不想搜索,'^$1'而是要搜索动态插入的固定字符串,该字符串仅在行首时才应匹配。这就是我的意思$1


您是否尝试过使用单引号而不是双引号,例如grep '^$1'?还是不是要防止$1外壳扩展外壳程序?
mnille '16

@mnille我不想搜索'^ $ 1',而是要搜索动态插入的固定字符串,该字符串仅在行首时才应匹配。这就是$ 1的意思。
PSkocik '16

3
您也可以这样做,grep但您必须首先在字符串中转义任何特殊字符,例如printf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
don_crissti

@don_crissti比其他一些答案要好。想要成为一个吗?
roaima '16

@roaima-我知道,但是这里已经有了很多答案,这(在vars中转义特殊字符)是我(和这里的其他一些用户)已经花了很长时间了...您可以随时添加如果您愿意,可以将其添加到您的答案中,我将在此处删除评论(不要忘记添加缺少的前括号)。
don_crissti

Answers:


7

我想不出一种使用此方法的方法grep^本身是正则表达式的一部分,因此使用它需要对正则表达式进行解释。它使用子串匹配的琐碎awkperl或什么:

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

要处理包含的搜索字符串\,您可以使用与123的答案相同的技巧:

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

这不适用于字符串,例如\/
123年6

@ 123确实,我添加了一个变体来处理该问题。
史蒂芬·基特

对于\\\/\/\/\\\\/\\///\\/程序中那样的复杂字符串,仍然会失败。据我所知,除非您事先知道将使用多少反斜杠,否则无法正确地避开awk中的反斜杠。
123年

1
@ 123谢谢,我已经适应了您遍历环境的技巧,以避免进行转义处理。
史蒂芬·基特

我仍然最喜欢这种解决方案。高效(awk +无需浪费时间环顾四周),快速启动(awk +无需设置状态所需的其他流程)使用标准工具,并且非常简洁。所有其他答案至少缺少其中一些。(效率是这里的强项,因为grep以无与伦比的速度而闻名。)
PSkocik's

14

如果只需要检查是否找到匹配项,则将所有输入行剪切为所需前缀($1)的长度,然后使用固定模式grep:

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

获取匹配行数也很容易:

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

或所有匹配行的行号(行号从1开始):

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

您可以将行号输入到headtail获取匹配行的全文,但是到那时,仅使用Python或Ruby之类的现代脚本语言就更容易了。

(以上示例假定Posix grep和cut。它们假定要搜索的文件来自标准输入,但可以很容易地改成采用文件名。)

编辑:您还应确保模式($1)不是零长度的字符串。否则cut失败说values may not include zero。另外,如果使用Bash,请使用set -o pipefail来捕获错误退出cut


10

一种使用perl的方法,它将尊重反斜杠

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

这将为命令设置环境变量v,然后在变量的索引为0(即行的开头)时进行打印。

您也可以在awk中做相同的事情

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

7

这是一个全bash选项,不是我建议bash用于文本处理,但是它可以工作。

#!/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 "%s\n" "$line"
done

该脚本计算len输入参数$ 1 的长度,然后在每行上使用参数扩展来查看前len几个字符是否与$ 1相匹配。如果是这样,它将打印该行。


4

如果你$1是纯ASCII和你grep-P选项(启用PCRE),你可以这样做:

#!/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"

这里的想法是grep -P允许正则表达式\xXX指定文字字符,其中XX该字符的十六进制ASCII值。即使是特殊的正则表达式字符,该字符也将按字面值进行匹配。

od用于将预期的行开头转换为十六进制值的列表,然后将它们串在一起,每个前缀以\xprintf 为前缀。 ^然后在此字符串之前添加以构建所需的正则表达式。


如果您$1是unicode,则这会变得相当困难,因为通过所输出的字符与十六进制字节之间没有1:1的对应关系od


3

作为过滤器:

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

在一个或多个文件上运行:

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

Perlre文档“引用元字符”部分说明:

引用元字符

在Perl反斜杠元字符是字母数字,例如\b\w\n。与其他一些正则表达式语言不同,没有不是字母数字的反斜杠符号。所以,什么是像\\\(\)\[\]\{,或\}总是被解释为一个文字字符,而不是一个元字符。曾经在一个常见的习惯用法中使用它来禁用或引用要用于模式的字符串中正则表达式元字符的特殊含义。只需引用所有非“单词”字符:

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

(如果use locale已设置,则取决于当前的语言环境。)如今,更常见的是使用quotemeta函数或元\Q 引号转义序列来禁用所有元字符的特殊含义,如下所示:

    /$unquoted\Q$quoted\E$unquoted/

请注意,如果在\Q和之间放置文字反斜杠(那些不在插补变量中)\E,则双引号反斜杠插补可能会导致混淆的结果。如果需要在其中使用文字反斜杠\Q...\E,请参阅perlop中的“解析引用结构的详细信息”

quotemeta\Qquotemeta中进行了充分描述。


3

如果您的grep具有-P选项(即PCRE),则可以执行以下操作:

grep -P "^\Q$1\E"

请参考此问题,如果需要,请参阅PCRE文档以获取详细信息。


2

如果有不使用的字符,则可以使用该字符标记行的开头。例如$'\a'(ASCII 007)。很难看,但是可以用:

{ 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

如果不需要匹配的行,则可以删除尾随sed并使用grep -qF。但是使用awk(或perl)要容易得多...


0

当您要查找不带循环
的文件时,可以使用:使用搜索字符串的长度剪切文件

  cut -c1-${#1} < file

查找固定的字符串并返回行号

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

将行号用于类似 sed -n '3p;11p' file

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

当您要删除这些行时,请使用

  sed "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed 's/:.*/d;/' | tr -d '\n')" file
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.