一位同事来找我,我认为这个问题很简单,但事实证明是挑战性的。挑战在于:给定输入字符串,可以使用哪些Unix命令打印字符串中的任何匹配模式?
假设我们有以下输入字符串。
12345 4444 abc 789012 xyz 1234567 def 987654321 qrz 60606
目标是打印出字符串中的任何5位或6位数字,但不打印任何4位或7位数字。
我们首先想到像这样使用sed:
echo "12345 4444 abc 789012 xyz 1234567 def 987654321 qrz 60606" |
sed 's/.*[^0-9]\{1\}\([0-9]\{5,6\}\).*/\1/g'
但是,此命令仅打印出任何匹配模式的最后一次出现。
我们最终想出了使用sed和grep -Eo的组合。
echo "12345 4444 abc 789012 xyz 1234567 def 987654321 qrz 60606" |
sed 's/^/ /' | sed 's/$/ /' | grep -Eo '[[:space:]]+[0-9]{5,6}[[:space:]]+' |
sed 's/ $//' | sed 's/^ //'
它有效,但看起来有点笨拙。还有更好的方法吗?
答案 0 :(得分:3)
GNU grep至少支持-o
,我认为它也在POSIX版本中。
-o, - 仅匹配 仅显示与PATTERN匹配的匹配行的一部分。
答案 1 :(得分:2)
tr
和grep
怎么样?
echo "12345 4444 abc 789012 xyz 1234567 def 987654321 qrz 60606" |
tr ' ' '\n' |
grep '^[[:digit:]]\{5,6\}$'
或者正如dmckee建议的那样,您可以使用-o
标记来跳过tr
阶段(如果您的grep
版本具有此标记):
echo "12345 4444 abc 789012 xyz 1234567 def 987654321 qrz 60606" |
grep -o '\<[[:digit:]]\{5,6\}\>'
答案 2 :(得分:0)
在linux box上工作
echo "12345 4444 abc 789012 xyz 1234567 def 987654321 qrz 60606"|egrep -o 's|[[:digit:]]{5,6} |p'
答案 3 :(得分:0)
如果您愿意,您实际上只能使用Bash内置功能执行此操作,而不使用tr
或sed
或grep
等外部实用程序:
INPUT='12345 4444 abc 789012 xyz 1234567 def 987654321 qrz 60606'
( set -f
for word in $INPUT ; do
if [[ $word =~ ^[0-9]{5,6}$ ]] ; then
echo $word
fi
done
)
(set -f
是禁用文件名扩展,以便我们可以将$INPUT
拆分为其组成单词,而不必担心它可能包含*
或会扩展的内容文件名列表。( ... )
包含set -f
的效果,因此我们不必担心周围的上下文是否真的要禁用文件名扩展。)
答案 4 :(得分:0)
这可能对您有用:
echo "12345 4444 abc 789012 xyz 1234567 def 987654321 qrz 60606" |
sed 's/\<[0-9]\{,4\}\>//g;s/\<[0-9]\{7,\}\>//g;s/[^0-9]\+/ /g'
12345 789012 60606
或者:
echo "12345 4444 abc 789012 xyz 1234567 def 987654321 qrz 60606" |
sed 'H;g;:a;s/\n\([0-9]\{5,6\}\)\> */\1 \n/;ta;s/\n[^ ]* /\n/;ta;s/..$//'
12345 789012 60606
答案 5 :(得分:0)
这会过滤每一行,只打印5或6位数字,但将其保留在一行
perl -ne 'print join(" ",grep /\b[0-9]{5,6}\b/, split)."\n";'
如果输入
12345 4444 abc 789012 xyz 1234567 def 987654321 qrz 60606
hello
66666
输出
12345 789012 60606
66666