【问题标题】:using awk to find special charecters in txt file使用 awk 在 txt 文件中查找特殊字符
【发布时间】:2020-04-27 09:53:53
【问题描述】:

我需要扫描具有许多不同特殊字符和值的文件。 给定一组特殊字符 - 我需要在它旁边提供值:

547 %$ 
236 \"
4523 &* 
8876 (*
8756 "/
...

我正在使用带有 gsub 的 awk 命令来按原样查找序列。

awk -v st="$match_string" 'BEGIN {gsub(/(\[|\]|\-|\$|\*|\:|\+|\"|\(|\))/,"\\\\&", st)} match($0,st) {print;exit}' file.txt

该命令效果很好,例如

> (*
>> 8876 (*

但是我在使用命令定位 \" 序列时遇到问题 我正在尝试向 gsub 添加不同的字符串来表示序列:

|\\|
|\\\\|
|\\\\"|
...

但结果总是:

> \"
>> 8756 "/

虽然我正在寻找的结果是:

> \"
>> 236 \"

似乎 gsub 不起作用,并且 \" 就像 " 有什么想法吗?

以下是运行的简短脚本 - - 它应该找到附加到 first_num 中的值的符号 - 接下来它应该打印文件中附加到找到的符号的第一个值

first_num=$1
echo "looking for : $first_num"
sym_to_check=$(awk -v s="$first_num"  '$0~s {if ($0~s)print $2}' temp.txt)
echo "symbol - $sym_to_check"
first_val=$(awk -v s="$sym_to_check" 'BEGIN {gsub(/(\[|\]|\-|\$|\^|\*|\:|\+|\"|\(|\))/,"\\\\&",s)} $0~s {if ($0~s)print; if ($0~s)exit}' temp.txt)
echo "first val- $first_val"

假设txt文件为:

547 %$ 
111 [*
222 ()
5655 (*
454 )"
35 #!
743 \"
657 #!
236 \"
4523 &* 
8876 (*
456 \"
8756 "/

第一次运行很好:

> bash temp1.sh 8876
    looking for : 8876
    symbol - (*
    first val- 5655 (*

脚本找到附加到 (* 但是下一次运行很糟糕:

> bash temp1.sh 236
looking for : 236
symbol - \"
first val- 454 )"

符号是正确的 - 寻找 \" 但是在搜索附加到它的第一个值时,它会寻找第一个带有 " 的符号 这给出了值 454 )" 而不是所需的 743 \"

【问题讨论】:

  • 哪些输入有效,哪些无效?提供您正在测试的输入和预期的输出
  • 在问题中包含minimal reproducible example
  • 诸如 \" 之类的序列不起作用 - 它们被翻译成 "
  • 好的,我们知道了,提供一个我们可以轻松复制粘贴并继续工作的示例
  • I see到目前为止,您尚未接受任何问题的答案。请阅读stackoverflow.com/help/someone-answers

标签: awk


【解决方案1】:

您使用 -v st="$match_string" 初始化 awk 变量 st 的方式是通过设计扩展转义序列(例如,"$match_string" 中的 \t 将成为 st 中的文字制表符字符)并且您'正在使用正则表达式运算符match(),但试图转义正则表达式元字符以使其表现得像在进行字符串而不是正则表达式匹配,然后您在整行上进行部分匹配(例如$0~85将匹配@ 987654330@) 而不是在特定字段上完全匹配 ($1==85)。

以下是您如何在不解释转义序列的情况下从 shell 初始化 awk 变量,然后将它们作为完全匹配的文字字符串或特定字段上的数字进行测试,而不是在整行中使用部分匹配的正则表达式:

$ match_string='\"'

$ st="$match_string" awk 'BEGIN{st=ENVIRON["st"]} $2==st{print; exit}' file
743 \"

$ awk 'BEGIN{st=ARGV[1]; ARGV[1]=""} $2==st{print; exit}' "$match_string" file
743 \"

$ awk 'BEGIN{st=ARGV[1]; ARGV[1]=""} $1==st{print; exit}' '743' file
743 \"

并非所有 awks 都支持 ENVIRON[],因此第一种方法不适用于所有 awks,但第二种方法可以。

请参阅How do I use shell variables in an awk script? 了解如何从 shell 设置 awk 变量,以及当您想要进行文字字符串比较时,通常只使用像 ==index() 这样的字符串运算符而不是使用像 ~ 这样的正则表达式运算符会更简单或match() 并尝试转义所有正则表达式元字符以使它们表现得像字符串一样。

如果你曾经想要转义所有正则表达式元字符,那么执行此操作的语法是:

gsub(/[^^]/,"[&]",st); gsub(/\^/,"\\^",st)

而不是您问题中的代码:

gsub(/(\[|\]|\-|\$|\*|\:|\+|\"|\(|\))/,"\\\\&", st)

请参阅 Is it possible to escape regex metacharacters reliably with sed 了解为什么这是正确的语法。

【讨论】:

  • 谢谢 - st="$match_string" awk 'BEGIN{st=ENVIRON["st"]} $2==st{print; exit}' 文件解决方案效果很好!!
猜你喜欢
  • 2012-06-18
  • 1970-01-01
  • 2019-06-14
  • 2020-01-12
  • 2017-10-02
  • 1970-01-01
  • 2018-10-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多