bash中来自非Ascii字符串的数字子串

时间:2018-05-23 23:07:50

标签: bash sed grep

我有一个从文件中读取的字符串,它包含所有类型的非ascii字符,如下所示

line=^AÀÀ^P^G^P^@^H15552655^@^@E$4c<84>%ÿ~^@^@^Ac<8f>/qu^Q»í&.WÈå

现在我只需要提取&#39; 15552655&#39;这个数字。

我尝试了什么:

line=$(sed -n '1p' < file)

number=$(echo "${line//[!0-9]/}")
              or
number=$(echo $line | sed 's/[^0-9]*//g')

但这会返回&#39; 155526554&#39;,所以我需要一种方法从连续包含至少4个连续数字的行中提取子字符串[保证该模式中至少有4个数字]

非常感谢任何帮助。

更新-1:

number=$(echo $line | sed 's/[^0-9]*\([0-9]\{1,\}\).*$/\1/')

这似乎适用于上述情况,但如果输入采用此格式

,则会失败
line=^AÀÀ^P^4G^P^@^H15552655^@^@E$4c<84>%ÿ~^@^@^Ac<8f>/qu^Q»í&.WÈå

在这种情况下,它返回4,即它返回第一轮数字。我需要添加一些说给我最长或超过4个数字的东西。

2 个答案:

答案 0 :(得分:1)

这个怎么样:

number=$(echo "$line" | tr -cs '0-9' '\n' | awk '{if (length>l) { n=$0; l=length }} END { print n }')

说明:如果字符串包含某些shell元字符,$line周围的双引号会阻止shell执行任何奇怪的操作。 tr -cs '0-9' '\n'用换行符替换不是数字的所有内容,“替换”替换字符的运行;这实际上产生了文件中的数字列表,每行一个。然后在awk中,{if (length>l) { n=$0; l=length }}表示对于每个输入行,如果其length比之前看到的l长(n),请将l设置为当前行, END { print n }到它的长度。 {{1}}部分使其在输入结束时打印最长的行。

答案 1 :(得分:0)

我的建议是,你将这行划分为以逗号分隔的数字,然后根据你的内心检查这些数字:

line="^AÀÀ^P^G^P^@^H15552655^@^@E$4c<84>%ÿ~^@^@^Ac<8f>/qu^Q»í&.WÈå"

number=$(echo $line | sed -E 's/[^0-9]+/,/g')
echo $number
==> ,15552655,84,8,

找到最长的是复杂的。这是一个解决方案,但Gordon Davisson的解决方案是单线解决方案。

#!/bin/bash


line="^AÀÀ^P^G^P^@^H15552655^@^@E$4c<84>%ÿ~^@^@^Ac<8f>/qu^Q»í&.WÈå"

number=$(echo $line | sed -E 's/[^0-9]+/\\n/g')
max_length=0
this_index=0
saved_index=-1

echo $number | 
{ while read num ; do
pieces[$this_index]=$num
this_length=$(echo $num | wc -c | sed 's/ //g')
if [ $this_length -gt $max_length ]  ; then
    max_length=$this_length
    saved_index=$this_index
fi
this_index=$(expr $this_index + 1)
done


echo maxnum is ${pieces[$saved_index]}

}