使用bash脚本从变量中提取子字符串

时间:2014-12-20 08:19:40

标签: bash awk

我有一个bash变量,其值如下:

10:3.0,16:4.0,32:4.0,39:2.0,65:3.0,95:4.0,110:4.0,111:4.0,2312:1.0

价值内没有空格。该值可以很长或很短。这里存在诸如65:3.0之类的对。我知道对的第一部分中的数字的值,比如65。我想提取数字3.0或对65:3.0。我不知道65的位置(偏移)。

我将非常感谢能够进行此类提取的bash脚本。感谢。

7 个答案:

答案 0 :(得分:5)

可能awk是最直接的方法:

awk -F: -v RS=',' '$1==65{print $2}' <<< "$var"
3.0

或者得到这对:

$ awk -F: -v RS=',' '$1==65' <<< "$var"
65:3.0

答案 1 :(得分:4)

这是一个纯粹的Bash解决方案:

var=10:3.0,16:4.0,32:4.0,39:2.0,65:3.0,95:4.0,110:4.0,111:4.0,2312:1.0

while read -r -d, i; do
    [[ $i = 65:* ]] || continue
    echo "$i"
done <<< "$var,"

如果break中只有一个echo "$i",或者您只想要第一个65:...,则可以在var之后使用3.0

获取值echo "${i#*:}"65


其他(纯Bash)方法,无需显式解析字符串。我假设您只是在字符串中查找第一个var=10:3.0,16:4.0,32:4.0,39:2.0,65:3.0,95:4.0,110:4.0,111:4.0,2312:1.0 value=${var#*,65:} value=${value%%,*} echo "$value" ,并且它出现在字符串中:

65

对于长字符串,这将非常慢!


与上面相同,但会输出与var=10:3.0,16:4.0,32:4.0,39:2.0,65:3.0,95:4.0,110:4.0,111:4.0,2312:1.0 tmpvar=,$var while [[ $tmpvar = *,65:* ]]; do tmpvar=${tmpvar#*,65:} echo "${tmpvar%%,*}" done 对应的所有值(如果没有,则输出无):

var=10:3.0,16:4.0,32:4.0,39:2.0,65:3.0,95:4.0,110:4.0,111:4.0,2312:1.0

IFS=, read -ra ary <<< "$var"
for i in "${ary[@]}"; do
    [[ $i = 65:* ]] || continue
    echo "$i"
done

同样的事情,对于长串来说这会很慢!


我在纯Bash中获得的最快速度是我原来的答案(并且10000个字段很好):

var=10:3.0,16:4.0,32:4.0,39:2.0,65:3.0,95:4.0,110:4.0,111:4.0,2312:1.0

[[ ,$var, =~ ,65:([^,]+), ]] && echo "${BASH_REMATCH[1]}"

事实上,不,我在纯Bash中获得的最快速度就是这个正则表达式:

awk

测试此vs 65:3.0

  • printf -v var '%s:3.0,' {100..11000} var+=65:42.0 time awk -F: -v RS=',' '$1==65{print $2}' <<< "$var" 在最后的位置:

    time { [[ ,$var, =~ ,65:([^,]+), ]] && echo "${BASH_REMATCH[1]}"; }
    

    显示0m0.020s(粗略平均值),而:

    65:3.0

    显示0m0.008s(粗略平均值)。

  • printf -v var '%s:3.0,' {1..10000} time awk -F: -v RS=',' '$1==65{print $2}' <<< "$var" 不在最后:

    time awk -F: -v RS=',' '$1==65{print $2;exit}' <<< "$var"
    

    显示0m0.020s(粗略平均值)并提前退出:

    time { [[ ,$var, =~ ,65:([^,]+), ]] && echo "${BASH_REMATCH[1]}"; }
    

    显示0m0.010s(粗略平均值),而:

    {{1}}

    显示0m0.002s(粗略平均值)。

答案 2 :(得分:3)

echo $var | tr , '\n' | awk '/65/' 

,其中

  • tr , '\n'将逗号变为新行
  • awk '/65/'选择65

echo $var | tr , '\n' | awk -F: '$1 == 65 {print $2}' 

,其中

  • -F:使用:作为分隔符
  • $1 == 65选择65行作为第一个字段
  • { print $2}打印第二个字段

答案 3 :(得分:3)

这是gnu awk

awk -vRS="(^|,)65:" -F, 'NR>1{print $1}' <<< "$var"
3.0

答案 4 :(得分:3)

使用grep:

grep -o '\b65\b[^,]*' <<<"$var"
65:3.0

grep -oP '\b65\b:\K[^,]*' <<<"$var"
3.0

\K选项忽略匹配模式之前的所有内容并忽略模式本身。它是-P命令的Perl兼容性(grep)。

答案 5 :(得分:2)

使用sed

sed -e 's/^.*,\(65:[0-9.]*\),.*$/\1/' <<<",$var,"

<强>输出:

65:3.0

有两种不同的方法可以防止{{1>}成为第一行最后一行。无论如何,添加65:3.0以包围变量以提供发生。下面,Gnu扩展名commas用于指定零或一个出现次数。

\?

无论字符串中出现何处,都处理sed -e 's/^.*,\?\(65:[0-9.]*\),\?.*$/\1/' <<<$var

答案 6 :(得分:1)

尝试egrep如下:

echo $myvar | egrep -o '\b65:[0-9]+.[0-9]+' |