unix 使用SED提取特定长度的子字符串

o8x7eapl  于 2022-11-04  发布在  Unix
关注(0)|答案(2)|浏览(288)

我有以下SED命令

echo "abcd_2222222233333333_jdkj" | sed -e 's/^\(.*\)_\(.*\)_\(.*\)$/\2_\1_\3/'

返回
2222222233333333333333333322222222333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
太好了,但我真的想
2222222 - 333333333_abcd_jdkj公司
这是可能的一个简单的调整或我需要一些非sed的解决方案?基本上,我知道的数字是16字节,但我需要把它分成两个8字节的数字。

siv3szwd

siv3szwd1#

您可以使用.{8}来精确匹配八个字符,而不是使用.*来匹配任意数量的字符。
下面的还使用sed -r来允许ERE语法,它需要的反斜杠更少,通常比默认的BRE更容易阅读。(在具有BSD风格工具的系统上,这可能是sed -E)。

sed -re 's/^(.*)_(.{8})(.*)_(.*)$/\2-\3_\1_\4/' <<<"abcd_2222222233333333_jdkj"

顺便说一句--我强烈建议使用[^_]*而不是.*,这样正则表达式就不能匹配不希望匹配的下划线。(.表示“任何字符”; [^_]意味着“除_之外的任何字符“)。这不仅仅是正确性增强--它还可以通过避免回溯(regex引擎意识到它匹配了太多的内容,需要撤消它以前的一些匹配)来使您的regex更快地求值。
还要考虑bash的内置regex支持:

string='abcd_2222222233333333_jdkj'
re='([^_]+)_([[:digit:]]{8})([[:digit:]]+)_(.*)'

if [[ $string =~ $re ]]; then
  result=${BASH_REMATCH[2]}-${BASH_REMATCH[3]}_${BASH_REMATCH[1]}_${BASH_REMATCH[4]}
  echo "Result is: $result"
else
  echo "No match found"
fi
gt0wga4j

gt0wga4j2#

解决方案按照上述评论者的提示工作

echo "abcd_2222222233333333_jdkj" | sed -e 's/^\(.*\)_\(.\{8\}\)\(.\{8\}\)_\(.*\)$/\2-\3_\1_\4/'

相关问题