使用 awk 更改文件中第 n 行的第 n 个字符

Using awk to make changes to nth character in nth line in a file

我写了一个awk命令

awk 'NR==5 {sub(substr(,14,1),(substr(,14,1) + 1)); print "test.py"}' > test.py

这试图更改 python 文件第 5 行的第 14 个字符。由于某种原因,这不会停止执行,我必须打破它。它还会删除文件的内容。

示例输入:

import tools

tools.setup(
    name='test',
    tagvisc='0.0.8',
    packages=tools.ges(),
    line xyz
)

`

输出:

import tools

tools.setup(
    name='test',
    tagvisc='0.0.9',
    packages=tools.ges(),
    line xyz
)

远离固定的行号(NR==5)和固定的字符位置(14),而是动态地寻找你想要的change/increment,例如:

$ cat test.py
import tools

tools.setup(
    name='test',
    tagvisc='0.0.10',
    packages=tools.ges(),
    line xyz
)

一个 awk 增加 10 的想法(第 3 行,行中的第 3 个数字字符串):

awk '
/tagvisc=/ { split([=11=],arr,".")                             # split line on periods
             sub("." arr[3]+0 "7","." arr[3]+1 "7")  # replace .<oldvalue>7 with .<newvalue>7; 7 == single quote
           }
1
' test.py

备注:

  • arr[3] = 10',; with arr[3]+0 awk 将获取最左边的全数字内容,去掉所有其他内容,然后添加 0,留下 arr[3] = 10;同样的逻辑适用于 arr[3]+1 (arr[3]+1 = 11);基本上是丢弃任何非数字后缀的技巧
  • 如果文件中有多行字符串 tagvisc='x.y.z' 那么这将在所有行中更改 z;我们可以通过添加更多逻辑来仅更改 first 的出现来解决这个问题,但我暂时不考虑它,假设这不是问题

这会生成:

import tools

tools.setup(
    name='test',
    tagvisc='0.0.11',
    packages=tools.ges(),
    line xyz
)

如果 objective 是用新值覆盖原始文件,您有几个选择:

# use temporary file:

awk '...' test.py > tmp ; mv tmp test.py

# if using GNU awk, and once accuracy of script has been verified:

awk -i inplace '...' test.py

像这样...

$ awk 'function join(a,k,s,sep) {for(k in a) {s=s sep a[k]; sep="."}  return s}
       BEGIN {FS=OFS="\""}
       /^tagvisc=/{v[split(,v,".")]++; =join(v)}1' file > newfile

如果我理解您现在需要做的事情的细微差别,您需要使用 "." 作为 fieldsep 将第 5 条记录的第一个字段拆分为一个数组,然后删除 "\"," 从数组的第三个元素的末尾开始(可选),然后递增数字并将字段放回原处。您可以这样做:

awk '{split(,a,"."); sub(/["],/,"",a[3]); =a[1]"."a[2]"."(a[3]+1)"\","}1'

(NR==5省略举例)

例子Use/Output

$ echo 'tagvisc="3.4.30"', | 
  awk '{split(,a,"."); sub(/["],/,"",a[3]); =a[1]"."a[2]"."(a[3]+1)"\","}1'
tagvisc="3.4.31",

我将重定向到一个临时文件,然后返回到原始文件。如果这不是您需要的,请告诉我。

加上NR == 5你会得到

awk 'NR==5 {split(,a,"."); sub(/["],/,"",a[3]); =a[1]"."a[2]"."(a[3]+1)"\","}1' test.py > tmp; mv -f tmp test.py

对第三个参数使用 GNU awk 来匹配 () 和“就地”编辑:

$ awk -i inplace '
    match([=10=],/^([[:space:]]*tagvisc=7)([^7]+)(.*)/,a) {
        split(a[2],ver,".")
        [=10=] = a[1] ver[1] "." ver[2] "." ver[3]+1 a[3]
    }
    { print }
' test.py

$ cat test.py
import tools

tools.setup(
    name='test',
    tagvisc='0.0.9',
    packages=tools.ges(),
    line xyz
)

使用 awk 更改文件中[mth]行的第 n 个字符:

$ awk 'BEGIN{FS=OFS=""}NR==5{=9}1' file # > tmp && mv tmp file

输出:

import tools

tools.setup(
    name='test',
    tagvisc='0.0.9',   <----- this is not output but points to what changed
    packages=tools.ges(),
    line xyz
)

解释:

$ awk '
BEGIN {
    FS=OFS=""    # set the field separators to empty and you can reference
}                # each char in record by a number
NR==5 {          # 5th record
    =9        # and 18th char is replaced with a 9
}1' file         # > tmp && mv tmp file # output to a tmp file and replace

注意: 如果您尝试用单字节字符替换多字节字符(例如 utf8 ä (0xc3 0xa4) 与 a (0x61) 将导致 0x61 0xa4)。当然,在您要替换的位置之前的 ä 会使您的计算减去 1。

哦,是的,您可以用多个字符替换一个字符,但反之则不行。