提问人:Ron 提问时间:11/9/2023 最后编辑:romainlRon 更新时间:11/10/2023 访问量:115
如何更改 VIM sed命令以在 bash 脚本中工作?
How do i change a VIM sedcommand to work in a bash script?
问:
我在 Vim 中有一个非常有用的 sed 命令,我想把它放在一个简单的 bashs cript 中。
但是我已经尝试了它的许多变体(疯狂地谷歌),但它不起作用......
在 Vim 中工作的 sed 字符串是:
%s/\( \)[0-9]\{8\}$/\=printf(' %08d', line('.'))/g
我试过了
sed -i "s/\( \)[0-9]\{8\}$/\=printf(' %08d', line('.'))/g"
和几种变体。
我想更改一行中的最后 8 位数字(行 van 的长度不同,但它们总是以空格和 8 位数字结尾。有时我需要删除和删除行,因此需要更改序列号(行号):
此外,我使用相同的 Vim sed 命令来更改单词,这样我就可以改用行号。例:
%s/LINENUMB/\=printf('%08d', line('.'))/g
在这里,我想用实际的 8 位行号更改单词。LINENUMB
它可以在 Vim 中工作,但我无法让它从终端或脚本中工作。
示例 1,我删除了 .现在我需要更改序列号:00000002
321321321321321321321321321321321321321321321321321321 00000001
6546546546546546546546546546546546546546546546546546546546546546 00000003
987987987987987987987987987987987987987987987987987987987 00000004
预期成果:
321321321321321321321321321321321321321321321321321321 00000001
6546546546546546546546546546546546546546546546546546546546546546 00000002
987987987987987987987987987987987987987987987987987987987 00000003
示例 2,我想更改为实际行号。假设它在文件中是行的:LINENUMB
00206206
987654321LINENUMB123456789
预期成果:
98765432100206206123456789
答:
假设:
- 一个文件可以包含这两种情况(最后一个字段中的 8 位序列号;行中的文本字符串)
LINENUMB
- 如果在一行中出现多次,则每次出现都将替换为相同的行号
LINENUMB
- 文件的第一行始终以 sequence 开头
00000001
示例数据:
$ cat raw.dat
321321321321321321321321321321321321321321321321321321 00000001
654654654XLINENUMBX546546546546546546546546546546546546546546546 00000003
^^^^^^^^ ^^^^^^^^
98798XLINENUMBX9879879879879879XLINENUMBX7987987987987987 00000004
^^^^^^^^ ^^^^^^^^ ^^^^^^^^
注意:文件不包含以下行;提供这些线条是为了直观地突出显示感兴趣的字符串^^^^^
一个想法:awk
awk '
{ lineno = sprintf("%08d",FNR) } # zero-pad current line number (FNR)
/LINENUMB/ { gsub(/LINENUMB/,lineno) } # replace all strings "LINENUMB" with the zero-padded line number
$NF+0 != FNR { $NF = lineno } # if last field is not same as current line number then update the field with the zero-padded line number
1 # print current line to stdout
' raw.dat
这将产生:
321321321321321321321321321321321321321321321321321321 00000001
654654654X00000002X546546546546546546546546546546546546546546546 00000002
^^^^^^^^ ^^^^^^^^
98798X00000003X9879879879879879X00000003X7987987987987987 00000003
^^^^^^^^ ^^^^^^^^ ^^^^^^^^
验证输出正确后,有几种方法可以修改代码以更新原始文件:
将输出重定向到临时/暂存文件(例如,),然后
tempfile
mv tempfile raw.dat
如果 OP 在支持下使用,则可以按如下方式修改代码:
GNU awk
-i inplace
awk -i inplace '{ lineno = sprintf("%08d",NR) } ...' raw.dat
评论
/LINENUMB/
/LINENUMB/ { gsub(/LINENUMB/,lineno) }
{ gsub(/LINENUMB/,lineno) }
sprintf("%08d",NR)
sprintf("%08d",FNR)
FNR
$NF+0 != FNR
perl -pe cmd
等效于 。它可以从管道或文件中获取 stdin 作为输入。sed cmd
Perl,将最后八位数字替换为行号:
perl -pe 's/\d{8}$/sprintf("%08d",$.)/e' file
Perl,将 LINENUMB 替换为 8 位行号:
perl -pe 's/LINENUMB/sprintf("%08d",$.)/ge' file
- 这两个替换可以组合成一个 perl 调用,与 sed 相同,两者之间有多个或分号。
-e
$.
是“行号”的 perlvar。s///e
表示您在替换字符串的替换端执行 commmand。sprintf
这里使用 Perl 中的 VS,因为我们要打印到字符串而不是直接打印到输出流。printf
评论
我会利用 GNU 来完成这项任务,让内容成为AWK
file.txt
ABLE 00000001
CHARLIE 00000003
DOG 00000004
ZEBRA 00000026
STUFFLINENUMB 00000027
然后
awk '{$NF=sprintf("%08d",NR);gsub(/LINENUMB/,$NF);print}' file.txt
给出输出
ABLE 00000001
CHARLIE 00000002
DOG 00000003
ZEBRA 00000004
STUFF00000005 00000005
Explantion:我使用 sprintf
函数将当前行 () 的编号转换为宽度为 8 或更大的前导零的字符串,然后将其分配给最后一个字段 (),将所有替换为最后一个字段和该行的内容。免责声明:我假设您的文件具有使用单空格字符分隔的字段。如果您想了解更多关于或阅读 8 个强大的 Awk 内置变量 – FS、OFS、RS、ORS、NR、NF、FILENAME、FNRNR
NF
LINENUMB
print
NF
NR
(在 GNU Awk 5.1.0 中测试)
评论
这些可能对你有用(GNU sed):
第一种情况:
sed = file | sed -E 'N;s/(.*)\n(.*) .*/\2 00000000\1/;s/(.* ).*(.{8})$/\1\2/'
在每行之前插入一行包含行号的行。
将生成的文件通过管道传递到另一个 sed 调用中。
在第二个 sed 调用中,获取两行并使用模式匹配将表示当前行号的字段替换为前面加上 8 个零的新行号。
将新行号字段减少到 8 位数字。
第二种情况:
sed '/LINENUMB/{p;=;d}' file |
sed -E '/LINENUMB/{N;s/\n/&00000000/;s/LINENUMB(.*)\n.*(.{8})$/\2\1/}'
使用与上述相同的技术,但仅适用于包含 的行。LINENUMB
注意第二种解决方案假定每行仅更换一次。LINENUMB
评论
sed =
grep -n ''
上一个:如何使用左零焊盘格式化双倍?
下一个:不能匹配两个相同的类型
评论
:s
=printf()
00000001
LINENUMB
printf
s//\=printf()/
sed
\=