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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25599654/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 11:16:07  来源:igfitidea点击:

Replace character in a string using awk or sed

bashunixawksed

提问by MJM

Given the string below, how can I replace 6th and 7th by getting 14th and 15th digit using awk or sed.

给定下面的字符串,如何通过使用 awk 或 sed 获取第 14 位和第 15 位数字来替换第 6 位和第 7 位。

xxxxx02xxxxxx89xx
xxxxx22xxxxxx33xx

output

输出

xxxxx89xxxxxx89xx
xxxxx33xxxxxx33xx

I am newbie here, sorry for my question.

我是这里的新手,很抱歉我的问题。

回答by rici

The sed command is straightforward, but hard to read:

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

sed 's/\(.....\)..\(......\)\(..\)//'

A possibly more maintainable solution can be had with Gnu awk(but not other awk varieties. However, see below.):

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

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

The FIELDWIDTHSvariable defines 5 fixed-width fields: the first 5 characters, the next two characters (positions 6 and 7); the next six characters (8 through 13); the next two characters (14 and 15); and the next (up to) 999 characters, which should be the rest of the line. (If you have longer lines, increase as necessary). Setting OFSto empty is often useful with fixed-length fields; it prevents awkfrom inserting spaces between fields in the output.

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

FIELDWIDTHSis a GNU awk extension. However, it is easy enough to reimplement in Posix awk. Here's a simple implementation:

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 = 
awk -v FIELDWIDTHS="5 2 6 2 999" -v OFS= -f fw.awk -f <(echo '{=;print}')
;
$ echo 'xxxxx03xxxxxx75xx' | sed -r 's/^(.{5})(..)(.{6})..//g' 
xxxxx03xxxxxx03xx
$ echo 'xxxxx03xxxxxx75xx' | sed  's/^\(.\{5\}\)\(..\)\(.\{6\}\)..//g'
xxxxx03xxxxxx03xx
= ""; k=1; for (i=1; i<=_FW_NF; ++i) { $i = substr(a, k, _FW_ARRAY[i]); k+=_FW_ARRAY[i]; } } } BEGIN{set_fieldwidth()} {fw_()}

As far as I know, only Gnu awk lets you mix program files and program text on the awkcommand-line. Posix requires the -f program-fileoption, which may be repeated, but does not require the -e program-textoption as implemented by Gnu awk. Consequently, if you want to use the above snippet with a command-line awk program, you need to do something like this:

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

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

(Assuming you put the fieldwidth snippet into fw.awk.)

(假设您将 fieldwidth 片段放入fw.awk.)

For efficiency, fw.awkinsists that you tell it that you've changed FIELDWIDTHSby calling fieldwidth_set(). Or you can use set_fieldwidth("....")to set FIELDWIDTHSto a new value. It will work with GNU awk as well as with other awk implementations; it lets GNU awk do the heavy lifting.

为了效率,fw.awk坚持告诉它你已经FIELDWIDTHS通过调用fieldwidth_set(). 或者您可以使用set_fieldwidth("....")设置FIELDWIDTHS为新值。它将与 GNU awk 以及其他 awk 实现一起工作;它让 GNU awk 完成繁重的工作。

回答by Avinash Raj

You could try the below sed command,

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

awk '{=;=}1' FS= OFS= file
xxxxx89xxxxxx89xx
xxxxx33xxxxxx33xx

It replaces 14th and 15th digits with the digits in the position 6 and 7th.

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

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

It replaces 6th and 7th digits with the digits in the position 14th and 15th.

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

回答by Jotne

This should follow your request and work with all awk:

这应该遵循您的要求并与所有人合作awk

awk 'sub(/[0-9]+/,substr(
awk '{print substr(
xxxxx89xxxxxx89xx
xxxxx33xxxxxx33xx
,0,5) substr(##代码##,14,2) substr(##代码##,8)}' file
,14,2))' file

It will change the digit in position 6by the one in 14and the one in 7with the one int 15

它将改变位置的数字6由一个 in14和一个 in7与一个 int15

If FS=""does not work, try this:

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

##代码##

As request in one of the comment:
It works, thanks! How about if I want to replace 14th and 15th digit by 6th and 7th digit? – Vision111

作为评论之一中的要求:
It works, thanks! How about if I want to replace 14th and 15th digit by 6th and 7th digit? – Vision111

##代码##

回答by Jotne

This will work without GNU awk GAWK

这将在没有 GNU awk 的情况下工作 GAWK

##代码##

Or longer but more generic

或者更长但更通用

##代码##

RESULT:

结果:

##代码##