这是一个后续先前的问题。我使用此语法是为了删除重复行,即使字段的间距不同
awk '{$1=$1};!NF||!seen[$0]++' /tmp/fstab
现在我想排除以 开头的行#
。所以我使用这个语法
awk '/^#/ || "'!'"'{$1=$1};!NF||!seen[$0]++' /tmp/fstab
-bash: !: event not found
我的语法有什么问题?
答案1
怎么样
awk '!NF||$1~/^#/ {print; next} {$1=$1} !seen[$0]++' /tmp/fstab
这将立即打印任何空行或其第一个字段以 开头的行#
,然后跳过执行,以便绕过任何进一步的代码。只要尚未遇到其他所有行,就会重建并打印它们。
$1~/^#/
检查 if而不是将匹配应用于整行(即简单地)的原因/^#/
是,这样我们还可以捕获 前面#
有空格的注释行。尽管联机帮助fstab
页要求为了符合注释行的资格,第一的字符必须是 a #
,正如 @StephenKitt 指出的,Linux 实现libmount
将跳过前导空格并接受一行作为注释第一个非空白字符是 a #
。
答案2
由于bash
正在抱怨(而不是awk
)并且您的周围有单引号,因此!
问题很明显:您正在退出 的命令块awk
。
awk '{$1=$1} /^#/ || !seen[$0]++' file
即先进行操作,然后进行检查。缺点:也会删除/减少注释中的空格,但不会删除此类重复项。通过首先缓冲该行来避免这种情况:
awk '{a=$0 ; $1=$1} /^#/ || !seen[$0]++ {print a}' file
输入:
#comment
duplicate line
#comment
duplicate line
not duplicate
not duplicate 2
duplicate line
#comment2
#comment2
#comment 3
#comment 3
输出(第一个代码)
#comment
duplicate line
#comment
not duplicate
not duplicate 2
#comment2
#comment2
#comment 3
#comment 3
输出(第二个代码)
#comment
duplicate line
#comment
not duplicate
not duplicate 2
#comment2
#comment2
#comment 3
#comment 3
答案3
GNU sed
扩展正则表达式模式打开-E
sed -Ee '
# print empty|blank|comment lines
/^\s*(#|$)/b
s/\s+/ /g;s/^ | $//g;G; # squeeze whitespace n append previous unique lines
/^([^\n]*)\n(.*\n)?\1(\n|$)/d; # delete if seen
P;h;d; # print seen first time then update seen list
' file