使用awk或sed替换字符串中的字符

时间:2014-09-01 06:02:28

标签: bash unix awk sed

如果给出下面的字符串,如何使用awk或sed获得第14和第15位来替换第6和第7位。

xxxxx02xxxxxx89xx
xxxxx22xxxxxx33xx

输出

xxxxx89xxxxxx89xx
xxxxx33xxxxxx33xx

我是新手,对不起我的问题。

4 个答案:

答案 0 :(得分:3)

sed命令很简单,但很难阅读:

sed 's/\(.....\)..\(......\)\(..\)/\1\3\2\3/'

可以使用Gnu awk(但不是其他awk变种)可能更易维护的解决方案。但是,请参见下文。):

gawk -v FIELDWIDTHS="5 2 6 2 999" -v OFS='' '{$2=$4;print}'

FIELDWIDTHS变量定义了5个固定宽度字段:前5个字符,后两个字符(位置6和7);接下来的六个字符(8到13);接下来的两个字符(14和15);和下一个(最多)999个字符,应该是该行的其余部分。 (如果你有更长的线,必要时增加)。将OFS设置为空对于固定长度字段通常很有用;它阻止awk在输出中的字段之间插入空格。

FIELDWIDTHS是GNU awk扩展。但是,在Posix awk中重新实现很容易。这是一个简单的实现:

function fieldwidth_set(         i) {
  if (PROCINFO["FS"]) FIELDWIDTHS = FIELDWIDTHS;
  else if (length(FIELDWIDTHS)) {
    _FW_NF = split(FIELDWIDTHS, _FW_ARRAY);
    for (i in _FW_ARRAY) {
      if (_FW_ARRAY[i] !~ /^[0-9]+$/) {
        printf "Illegal value '%s' in FIELDWIDTHS\n", _FW_ARRAY[i] >>"/dev/stderr";
        exit 1;
      }
      _FW_ARRAY[i]+=0;
    }
  } else
    _FW_NF = 0;
}
function set_fieldwidth(fw) { FIELDWIDTHS=fw; fieldwidth_set(); }
function fw_(               a,i,k) {
  if (_FW_NF) {
    a = $0;
    $0 = "";
    k=1;
    for (i=1; i<=_FW_NF; ++i) { 
      $i = substr(a, k, _FW_ARRAY[i]);
      k+=_FW_ARRAY[i];
    }
  }
}
BEGIN{set_fieldwidth()}
{fw_()}

据我所知,只有Gnu awk允许您在awk命令行上混合程序文件和程序文本。 Posix需要-f program-file选项,可以重复,但不需要Gnu awk实现的-e program-text选项。因此,如果您想将上述代码段与命令行awk程序一起使用,则需要执行以下操作:

awk -v FIELDWIDTHS="5 2 6 2 999" -v OFS= -f fw.awk -f <(echo '{$2=$4;print}')

(假设您将fieldwidth代码段放入fw.awk。)

为提高效率,fw.awk坚持要求您通过致电FIELDWIDTHS告诉您已更改fieldwidth_set()。或者,您可以使用set_fieldwidth("....")FIELDWIDTHS设置为新值。它将与GNU awk以及其他awk实现一起使用;它让GNU awk做了繁重的工作。

答案 1 :(得分:2)

你可以试试下面的sed命令,

$ echo 'xxxxx03xxxxxx75xx' | sed -r 's/^(.{5})(..)(.{6})../\1\2\3\2/g' 
xxxxx03xxxxxx03xx
$ echo 'xxxxx03xxxxxx75xx' | sed  's/^\(.\{5\}\)\(..\)\(.\{6\}\)../\1\2\3\2/g'
xxxxx03xxxxxx03xx

它用位置6和7中的数字替换第14和第15位数字。

$ echo 'xxxxx03xxxxxx75xx' | sed -r 's/^(.{5})..(.{6})(..)/\1\3\2\3/g'
xxxxx75xxxxxx75xx
$ echo 'xxxxx03xxxxxx75xx' | sed 's/^\(.\{5\}\)..\(.\{6\}\)\(..\)/\1\3\2\3/g'
xxxxx75xxxxxx75xx

它用第14和第15位的数字替换第6和第7位数字。

答案 2 :(得分:2)

这应该遵循您的请求并与所有awk合作:

awk '{$6=$14;$7=$15}1' FS= OFS= file
xxxxx89xxxxxx89xx
xxxxx33xxxxxx33xx

它会将位置6中的数字更改为14中的数字,将7中的数字更改为15

如果FS=""不起作用,请尝试以下操作:

awk '{n=split($0,a,"");a[6]=a[14];a[7]=a[15];for (i=1;i<=n;i++) printf "%s",a[i];print ""}' input

在其中一条评论中提出要求:
It works, thanks! How about if I want to replace 14th and 15th digit by 6th and 7th digit? – Vision111

awk '{$14=$6;$15=$7}1' FS= OFS= file

答案 3 :(得分:1)

这将在没有GNU awk GAWK

的情况下发挥作用
awk 'sub(/[0-9]+/,substr($0,14,2))' file

或更长但更通用的

awk '{print substr($0,0,5) substr($0,14,2) substr($0,8)}' file

结果:

xxxxx89xxxxxx89xx
xxxxx33xxxxxx33xx