如何更新文本行的某些位置(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
您好,我是 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
将 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