在 shell 脚本中,我想使用 sed 将1bc1034gf45dna22
(总共 16 个字符)替换为1b:c1:03:4g:f4:5d:na:22
(用冒号分隔)。
编辑
我试过了
sed 's/\w{2}/\w{2}:/g' a.txt > b.txt
哪里a.txt
有
1bc1034gf45dna22
Sed 不是这项工作的理想工具,因为有太多的边缘情况。如果您有非常规则的数据和已知的语料库,那很好,但在某些情况下,您需要更强大的东西,可以在匹配/捕获感兴趣的文本后独立地作用于一行。例如,给定一个包含以下内容的输入文件:
foo 1bc1034gf45dna22 bar
您可能需要提取第二列,对其进行转换,然后将其替换到位。您可以使用 Ruby 执行此操作,如下所示:
$ echo 'foo 1bc1034gf45dna22 bar' |
ruby -pe '
if /(?<str>\p{Alnum}{16})/ =~ $_
$_.sub!(str, str.scan(/../).join(?:))
end'
这正确地产生:
foo 1b:c1:03:4g:f4:5d:na:22 bar
这可能对您有用(GNU sed):
sed 's/\w\w\B/&:/g' file
做
sed -e 's/../&:/g' -e 's/:$//' a.txt > b.txt
或者
sed -e 's/\(..\)/\1:/g' -e 's/:$//' a.txt > b.txt
为你工作?
为什么不 sed 's/1bc1034gf45dna22/1b:c1:03:4g:f4:5d:na:2/g' file
呢?
在任何 GNU/Linux 发行版上使用 GNU/sed,您都可以使用扩展的正则表达式。这会将任意长度的字符串转换为每两个字母用冒号分隔的字符串:
echo 1bc1034gf45dna22 | sed -re 's/(\w{2})/\1:/g' -e 's/:$//'
在您的 AIX 平台上,您可以利用 awk:
echo 1bc1034gf45dna22 | awk '
BEGIN { FS=""; ORS=""; }
{
for (i=1; i <=NF; i++) {
if (i > 1 && (i + 1) % 2 == 0) {
print(":");
}
print($i);
}
}'
你可以:
sed -i 's/\(\w\{2\}\)/\1:/g' file
这也会在字符串的末尾附加一个 :。由于我们不能在 sed 正则表达式语法中使用积极的前瞻,因此我们需要:
sed -i 's/:$//g' file
请注意,我们对 sed 使用了就地编辑,因此文件将以这种方式更改。
或者,您可以使用 perl 来使用 /(\w{2})(?=\w{2})/$1:/g 的正则表达式
好吧,总是有蛮力方法:
sed 's/\<'\
'\([0-9a-z][0-9a-z]\)'\
'\([0-9a-z][0-9a-z]\)'\
'\([0-9a-z][0-9a-z]\)'\
'\([0-9a-z][0-9a-z]\)'\
'\([0-9a-z][0-9a-z]\)'\
'\([0-9a-z][0-9a-z]\)'\
'\([0-9a-z][0-9a-z]\)'\
'\([0-9a-z][0-9a-z]\)'\
'\>/\1:\2:\3:\4:\5:\6:\7:\8/g'
在延续线上没有前导空格的情况下,shell 将字符串正确地粘贴在一起。