如何更新文本行的某些位置(Bash 中的子字符串)

How to update certain positions of a text line (substring in Bash)

您好,我是 shell 编程的新手,我遇到了以下问题,我正在合并两个文件,因此我需要更新代表新文件中行数的位置的页脚文件,原始页脚如下所示:

90000000000100000000000012345...n
90000000000300000000000012345...n

行数表示在位置2到13例如

9[000000000010]0000000000012345...n
9[000000000030]0000000000012345...n

我正在使用以下指令

newfooter=`sed 1d $newfile | awk -v completeline=$originalfooter'{total_lines+=1}END{printf "%1d%012d%d\n", substr(completeline, 1, 1), total_lines, substr(completeline, 14)}'`

但我的结果如下:

90000000000412345...n

正如你所看到的,总行的总和是可以的一次 000000000010 + 000000000030 = 000000000040 但是接下来的 11 个位置都丢失了,结果我我试图得到应该如下:

90000000000400000000000012345...n

老实说,我完全迷路了,谢谢你的帮助

我认为您在 printf.

的最后一部分缺少零填充

尝试更改您的 printf "%1d%012d%d\n" 通过 printf "%1d%012d%017d\n".

这应该会告诉 printf 代码您需要 17 位数字作为最后一个数字,如果数字小于这 17 位数字,则在左侧填充零。

上面看起来很接近(确切?)但我认为这也有效:

Mac_3.2.57$newfooter=`cat newfile | awk -v completeline=$originalfooter '{total_lines+=1}; END {printf("%s%012.12d%s\n", substr(completeline, 1, 1), total_lines, substr(completeline, 14))}'`
Mac_3.2.57$echo $newfooter
90000000000300000000000012345...n
Mac_3.2.57$cat newfile | wc -l
      30
Mac_3.2.57$

sed 可能是一个更好的操作字符串的工具

originalfooter='90000000000300000000000012345...n'
# format number
num=$(printf "%012d" 57)
# replace in original footer
echo "$originalfooter" | sed -re "s/([0-9])[0-9]{12}(.*)/$num/" 

# result: 90000000000570000000000012345...n

有点不同的方法

originalfooter='90000000000300000000000012345...n'
num=$(printf "%012d" 57)
newFooter=$(sed -re "s/([0-9])[0-9]{12}(.*)/$num/" <<< "$originalfooter")
echo "$newFooter"

虽然其他人建议将 %d 更改为 %012d(或 %017d),但问题要简单一些。

考虑以下几点:

awk -v x='000001' 'BEGIN{printf "%d", x}'
1                                          # leading zeros are dropped

awk -v x='000001' 'BEGIN{printf "%06d",x}'
000001                                     # leading zeros are dropped and then added back

这些示例 (%d / %06d) 告诉 printf 将参数视为 integer/numeric。

正如 OP 在评论中提到的那样,真正需要的是保留构成 'rest of the line' 的任何内容。

我们可以通过用 %s 关闭 %d 来完成此操作,它告诉 printf 它正在处理一个字符串:

awk -v x='000001' 'BEGIN{printf "%s", x}'
000001                                     # string is printed as is, no dropping/adding of 0's

这意味着 OP 应该能够通过以下方式获得所需的输出:

printf "%1d%012d%s\n" ...

事实上,前导 %1d 也可以替换为 %s

printf "%s%012d%s\n" ...

注意: %s 用于未更改的 'footer' 部分意味着非数字(如果它们可能存在)如果使用 %d

,将被保留而不是导致问题 and/or 被删除

将 OP 的 awk 代码缩减为演示:

$ x='90000000000100000000000012345...n'

# current printf format:

$ awk -v x="${x}" 'BEGIN{printf "%1d%012d%d\n", substr(x,1,1), "40", substr(x,14)}'
900000000004012345

# proposed printf format:

$ awk -v x="${x}" 'BEGIN{printf "%s%012d%s\n", substr(x,1,1), "40", substr(x,14)}'
90000000000400000000000012345...n