将 grep 与包含要扩展的变量的模式结合使用

将 grep 与包含要扩展的变量的模式结合使用

我有一个表格文件

2e95d7582c53583fa8afb54e0fe7a2597c92cbba 1461065389 52880 temp/hello/file.txt
46c897a7aa8a641f46080b3431860bd0cd4a8f05 1461066221 207 temp/Another file.txt
83c8ce6b163ec1c615617fa0dbde9e928bc3daf4 1461056193 86112 Pictures/a photo.jpg
...

也就是说,每一行都有一个 40 个字符长的十六进制数字,后跟空格、整数、空格、整数、空格以及可能包含空格的文件路径。每条道路都是独一无二的。

在 bash 脚本中,我的变量与文件中的一行具有相同的形式,只是没有第一个十六进制字符串和空格(第一个 41 个字符),例如:

myvar="1461066221 207 temp/Another file.txt"

我的目标是找到文件中匹配的行myvar 确切地当前 41 个字符被忽略时。如果找到这样的匹配,我希望将变量line设置为文件中的整行。对于上面的示例,line将设置为

46c897a7aa8a641f46080b3431860bd0cd4a8f05 1461066221 207 temp/Another file.txt

如果没有这样的匹配,line应该设置为空字符串,或者不设置。

我的解决方案是这样的(filelist是文件名):

line=$(grep --color=never -E "^.{41}$myvar$" $filelist)

一个问题是,当$myvar展开时,它可能包含特殊符号,如.+、 Even^$等,这些符号对 具有特殊含义grep。我想grep表演一个精确的匹配myvar一行中除前 41 个字符之外的所有字符。

答案1

Perl 来救援!

perl -ne 'BEGIN { $search = shift }
          print if /^.{41}\Q$search\E$/;
         ' -- "$myvar" "$filelist"
  • -n逐行读取文件。
  • BEGIN 块将第一个参数中的 $myvar 检索到 Perl 变量 $search 中。
  • \Q...\E引用内部部分(参见引用元)。这处理变量可以包含的所有特殊字符。不要忘记双引号 shell 变量!

答案2

export myvar
awk 'substr($0, 42) == ENVIRON["myvar"]' < "$filelist"

答案3

这是一条不同的路;它首先将 'line' 设置为空,如果发现 'myvar' 与尾随 3 个字段匹配则设置它。

line=
while IFS=' ' read -r hex int1 int2 rest
do
  if [[ "$myvar" = "$int1 $int2 $rest" ]]
  then
    line="$hex $int1 $int2 $rest"
  fi
done < filelist

这是另一种方法,使用 bash 的mapfile内置和第二个临时关联数组:

mapfile -t < filelist # sets MAPFILE array
declare -A temparray
shopt -s extglob
for val in "${MAPFILE[@]}"
do 
  short="${val##*([^ ]) }"
  temparray[$short]="$val"
done
line=${m[$myvar]}
unset -v MAPFILE temparray val short

这会将文件放入索引数组 MAPFILE 中,然后我们对其进行循环。该循环将“short”变量设置为该行的“后缀”部分 - 它删除与“零个或多个非空格后跟空格”模式匹配的前导值,然后设置“$”的关联数组值短”为整行(“$val”)。进行这种匹配需要*生效shopt -s extglob。然后我们将 line 设置为结果值(或者如果该值不存在于数组中,bash 将返回空/空值)。

相关内容