Ayl*_*lox 4 command-line bash special-characters grep text-processing
我发现了很多非常相似的问题,但不完全是这个。我有一个包含以下内容的文本文件(无重复,每行固定 4 个字符):
A1234
G1234
$1234
M1234
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用 grep 搜索以字符 $char 开头的行,该行是通过使用 $char 定义搜索项输入的,并将其后面的四个数字分配给 $numbr。它看起来是这样的:
numbr=`grep ^"${char}" file.txt | cut -c 2,3,4,5`
Run Code Online (Sandbox Code Playgroud)
这适用于我需要的任何字符,但美元符号除外,美元符号会使 $numbr 为空。
输入字符 $char 预先定义如下,如果有帮助的话:
char="`dd if=text.txt ibs=1 skip=$skipcount count=1`"
Run Code Online (Sandbox Code Playgroud)
($skipcount 是一个整数)
我尝试了使用和不使用 -E 标志,以及我能找到的转义 $char 值的各种方法。我不需要专门使用 grep,到目前为止我只是使用它取得了最大的成功。
我已经坚持这个问题有一段时间了,所以任何帮助将不胜感激。如果我成功复制了一篇文章,我深表歉意,感谢所有在这里做出贡献的人,我在一两分钟内找到了几乎所有问题的解决方案。
编辑:对我不小心删除了评论的人表示抱歉。要点是他建议回声和管道,类似这样的东西(我认为这是部分的,我需要填写其余的):
echo "${char}" | grep '^\$'
Run Code Online (Sandbox Code Playgroud)
不为我工作。我也不够清楚 - 在 .txt 中的每个字符串(例如 A1234)中,只有第一个字符被分配给 $char。$char 之后的 4 个数字是我需要分配给 $numbr 的内容,并且该字符串可以出现在 .txt 文件中的任何行。每行上不会有其他字节。
$在正则表达式(行尾)中具有特殊含义...因此,为了轻松匹配它,需要通过例如用反斜杠转义它来剥离该特殊含义\...要动态地做到这一点,您可以使用 Bash 的参数扩展如下${char/\$/\\$}:
grep -Po "^${char/\$/\\$}\K[[:digit:]]+" file.txt
Run Code Online (Sandbox Code Playgroud)
... 在哪里:
grep的选项-Po将启用Perl风格的正则表达式(需要\K)并且仅打印匹配的捕获组。
^将匹配行的开头。
${char/\$/\\$}双引号内的内容" ... "将被 shell (Bash) 扩展为变量,char替换第一次出现的(从左侧)$(如果找到),并将\$其传递到命令行,并在其前面添加转义字符,以便匹配从字面上看,稍后由grep. 1
Perl\K将从打印中排除左侧的匹配部分(将重置此时的匹配),因此只有右侧的匹配部分[[:digit:]]+将被打印...仍然是整个表达式的左侧和右侧将被评估并且必须按该顺序在输入行中匹配。
[[:digit:]]+将匹配一个数字[[:digit:]](包括任何类型的 UNICODE)至少一次+。
1 ) 对于不支持 Bash${var/find/replace}类型的参数扩展的其他 shell,您可以在方括号内使用正常的参数扩展,就像[${char}]当该参数在 内部扩展时[],生成的字符 例如$将被视为垃圾。
...并在变量赋值中使用它,如下所示:
numbr=$(grep -Po "^${char/\$/\\$}\K[[:digit:]]+" file.txt)
Run Code Online (Sandbox Code Playgroud)
请注意命令替换的旧表示法,即反引号“`...`”现在是一个遗留兼容性功能,并且已被弃用,以支持当前的命令替换表示法$(...)...因此,请使用后者。
其他 nonegrep解决方案(为了提高可移植性,因为grep的-P选项可能不会在所有实现中出现/受支持)包括:
和awk:
awk -F"${char}" '$2~"^[[:digit:]]+$" {print $2}' file.txt
Run Code Online (Sandbox Code Playgroud)
...其中字段分隔符设置为${char},然后如果第二个字段都是数字$2~"^[[:digit:]]+$",则打印它print $2。
和sed:
sed -nE "s/^([${char}])([[:digit:]]+)$/\2/p" file.txt
Run Code Online (Sandbox Code Playgroud)
...其中-nE将默认不打印并启用扩展正则表达式来处理例如[]和捕获组(),然后"..."脚本字符串周围的双引号将允许 shell 进行参数扩展,以便${char}扩展为其值,并且如果正则表达式表达式在一行中匹配,然后匹配的数字被分配给第二个捕获组,([[:digit:]]+)即并通过其参考数字调用\2来替换整个匹配,然后使用命令打印p。
和perl:
export char; perl -lne 'print $1 if /^\Q$ENV{char}\E(\d+)$/' file.txt
Run Code Online (Sandbox Code Playgroud)
...其中-n默认不打印,如果正则表达式匹配,将打印ie (缩写)print $1中的第一个捕获组。(...)(\d+)([[:digit:]]+)
请注意,export char为了从\Q和之间的 Perl 脚本调用该变量作为环境变量,这是为了在扩展\E为 时正确处理正则表达式,并且可能不起作用...否则,如果不是正则表达式:char$$]$
perl -lne "/(?<=^[${char}])([[:digit:]]+)$/ and print $&" file.txt
Run Code Online (Sandbox Code Playgroud)
...其中-n默认为不打印,双引号"..."将允许发生 shell 参数扩展,并且后向查找(?<=...)将匹配,但在非捕获(无打印)组中,并将print $&打印来自捕获组的匹配。