使用 sed 打印 4 个单词的行

使用 sed 打印 4 个单词的行

我在 Ubuntu 20.04 中使用 Bash。

我有文件:

Hello hi 123
if a equals b
you
one abc two three four
dany uri four 123

我需要找到sed只有-只有4个单词的行。这是我写的代码,它不起作用,它准确地打印了文件。

sed "/[a-Z0-9+]{4}/g" F1

答案1

这确实应该通过一个可以轻松计算字段的工具来解决,例如awk

$ awk 'NF == 4' file
if a equals b
dany uri four 123

这使用了NF一个特殊变量,awk它将保存当前记录中的字段数。默认情况下,一条记录是一行,字段是由一个或多个空白字符(制表符或空格)分隔的任何子字符串,不包括行开头或结尾的空字段。上面的短awk程序将输出恰好包含四个字段的任何行。


使用 时sed,您需要匹配空白分隔的子字符串。

请注意,sed默认情况下使用基本正则表达式,并且您显示的表达式使用{4},它是扩展正则表达式修饰符。基本正则表达式中的等效内容将被编写\{4\}。您还使用了无效的字符范围 ,a-Z并且您打算使用的字符类最好写为[[:alnum:]],即与任何字母数字字符匹配的内容(假设包含+是拼写错误)。尾随g命令(从“保留空间”获取数据)似乎放错了地方。

我在这里的总体想法是将每个单词(一个或多个非空白字符的运行)压缩为单个x单词,然后删除所有空白字符(制表符或空格)。如果结果字符串恰好是xxxx,则打印原始行(否则删除该行并立即开始下一个循环)。

sed -e h \
    -e 's/[^[:blank:]]\{1,\}/x/g' \
    -e 's/[^x]//g' \
    -e '/^xxxx$/!d' \
    -e g file

这里,原始行首先用 保存到“保留空间” h,然后如果需要打印,则再次取出,g最后用 。如果d执行倒数第二行的命令,则g永远不会考虑最后一行。

或者,使用扩展正则表达式:

sed -E -e h \
    -e 's/[^[:blank:]]+/x/g' \
    -e 's/[^x]//g' \
    -e '/^xxxx$/!d' \
    -e g file

测试:

$ sed -e h \
>     -e 's/[^[:blank:]]\{1,\}/x/g' \
>     -e 's/[^x]//g' \
>     -e '/^xxxx$/!d' \
>     -e g file
if a equals b
dany uri four 123

[[:alnum:]]如果您希望单词字符由类而不是[^[:blank:]](非空白)定义,则将上面的表达式更改[^[:blank:]]为。[[:alnum:]]不同之处在于,诸如GNU/Linux或 之类的字符串Unix-system将被视为两个单词,而不是每个单词。

答案2

使用 GNU sed

$ sed -E '/^\s*(\w+\s+){3}\w+\s*$/!d' infile
if a equals b
dany uri four 123

POSIXly;你可以写:

sed '/^[[:space:]]*\([_[:alnum:]][_[:alnum:]]*[[:space:]][[:space:]]*\)\{3\}[_[:alnum:]][_[:alnum:]]*[[:space:]]*$/!d' infile

答案3

利用GNU sed我们创建的正则表达式,它查看可选的前导空格,后跟正好 4 对非空白+空白,后跟模式空间的结尾。

$ sed -nE 'G;/^\s*(\S+\s+){4}$/P' F1

或者,

sed -nE '
  s/\S+/&/4;T    # 3 or less chunks
  s//&/5;t       # 5 or more chunks 
  p              # exactly 4 chunks 
' F1

sed -E '
  s/\S+/&/5; td     # 5 or more chunks
  s//&/4; t         #  exactly 4 chunks
  :d;d              # 3 or less or 5 or more
' F1

答案4

显然awk对于这个用例来说这是更好的工具——但是OP指定了sed

使用 GNUsed可以实现多种解决方案。这是使用保留空间的一个:

$ cat -A file
Hello hi 123$
if a equals b$
you$
one abc two three four$
dany uri four 123$
   one two three four$
    five  six ^Iseven eight      $

$ sed -e 'h; s/^\s*//; s/\s*$//' -nre '/^\w+(\W+\w+){3}$/{g;p}' file
if a equals b
dany uri four 123
   one two three four
    five  six   seven eight      
$

sed命令可以简化为:

$ sed -nr '/^\s*(\w+)(\W+\w+){3}\s*$/p' file

这是上一个sed命令的另一个更可移植的版本,它使用 POSIX 字符类 和-E而不是-r

$ sed -En '/^[[:blank:]]*[[:alnum:]]+([[:blank:]]+[[:alnum:]]+){3}[[:blank:]]*$/p' file

相关内容