【发布时间】:2015-05-08 13:19:06
【问题描述】:
我需要修改的文件包含以下内容:
block: 16, size: 16, start: 8, length: 4
我想要该文件,以便 block、size 的值除以 2,而 start、 的值长度将乘以 2。
由于我必须对一大堆文件进行此类修改,我正在考虑使用 Sed 来为我做替换工作。但我不确定匹配和替换过程中是否允许计算。
【问题讨论】:
我需要修改的文件包含以下内容:
block: 16, size: 16, start: 8, length: 4
我想要该文件,以便 block、size 的值除以 2,而 start、 的值长度将乘以 2。
由于我必须对一大堆文件进行此类修改,我正在考虑使用 Sed 来为我做替换工作。但我不确定匹配和替换过程中是否允许计算。
【问题讨论】:
我总是尝试使用sed 解决带有sed 标记的每个问题。但是在这里很容易用awk 完成你想要做的事情。 (并且在这种情况下使用sed 太难了。)所以,这是我使用awk 的解决方案:
$ echo "block: 16, size: 16, start: 8, length: 4" | awk '{
printf "%s %d, %s %d, %s %d, %s %d\n", $1, $2/2, $3, $4/2, $5, $6*2, $7, $8*2
}'
block: 8, size: 8, start: 16, length: 8
【讨论】:
"block: 16, start: 8, size: 8, length: 4"
(执行此操作的正确工具是 awk,但为了获得 sed 练习的乐趣...)
在 sed 中是可能的。毕竟,根据一些简单的规则,乘以 2 是最后一位数字的替换:
要注意进位,每个规则应该写两次。
这个可以使用sed -f script 运行的 sed 脚本将输入行上的所有数字乘以 2:
s/$/\n\n/
:loop
s/0\n1\n/\n\n1/;t loop
s/0\n\n/\n\n0/;t loop
s/1\n1\n/\n\n3/;t loop
s/1\n\n/\n\n2/;t loop
s/2\n1\n/\n\n5/;t loop
s/2\n\n/\n\n4/;t loop
s/3\n1\n/\n\n7/;t loop
s/3\n\n/\n\n6/;t loop
s/4\n1\n/\n\n9/;t loop
s/4\n\n/\n\n8/;t loop
s/5\n1\n/\n1\n1/;t loop
s/5\n\n/\n1\n0/;t loop
s/6\n1\n/\n1\n3/;t loop
s/6\n\n/\n1\n2/;t loop
s/7\n1\n/\n1\n5/;t loop
s/7\n\n/\n1\n4/;t loop
s/8\n1\n/\n1\n7/;t loop
s/8\n\n/\n1\n6/;t loop
s/9\n1\n/\n1\n9/;t loop
s/9\n\n/\n1\n8/;t loop
s/\n1\n/\n\n1/;t loop
s/\(.\)\n\n/\n\n\1/;t loop
s/^\n\n//
将偶数除以 2,逻辑相同,但从左到右而不是从右到左:
s/^/\n\n/
:loop
s/\n1\n0/5\n\n/;t loop
s/\n\n0/0\n\n/;t loop
s/\n1\n1/5\n1\n/;t loop
s/\n\n1/\n1\n/;t loop
s/\n1\n2/6\n\n/;t loop
s/\n\n2/1\n\n/;t loop
s/\n1\n3/6\n1\n/;t loop
s/\n\n3/2\n1\n/;t loop
s/\n1\n4/7\n\n/;t loop
s/\n\n4/2\n\n/;t loop
s/\n1\n5/7\n1\n/;t loop
s/\n\n5/2\n1\n/;t loop
s/\n1\n6/8\n\n/;t loop
s/\n\n6/3\n\n/;t loop
s/\n1\n7/8\n\n/;t loop
s/\n\n7/3\n1\n/;t loop
s/\n1\n8/9\n\n/;t loop
s/\n\n8/4\n\n/;t loop
s/\n1\n9/9\n1\n/;t loop
s/\n\n9/4\n1\n/;t loop
s/\n1\n/5\n\n/;t loop
s/\n\n\(.\)/\1\n\n/;t loop
s/\n\n$//
结合这些,这个脚本可以完成工作:
h
s/, start.*//
s/^/\n\n/
t loopa
:loopa
s/\n1\n0/5\n\n/;t loopa
s/\n\n0/0\n\n/;t loopa
s/\n1\n1/5\n1\n/;t loopa
s/\n\n1/\n1\n/;t loopa
s/\n1\n2/6\n\n/;t loopa
s/\n\n2/1\n\n/;t loopa
s/\n1\n3/6\n1\n/;t loopa
s/\n\n3/2\n1\n/;t loopa
s/\n1\n4/7\n\n/;t loopa
s/\n\n4/2\n\n/;t loopa
s/\n1\n5/7\n1\n/;t loopa
s/\n\n5/2\n1\n/;t loopa
s/\n1\n6/8\n\n/;t loopa
s/\n\n6/3\n\n/;t loopa
s/\n1\n7/8\n\n/;t loopa
s/\n\n7/3\n1\n/;t loopa
s/\n1\n8/9\n\n/;t loopa
s/\n\n8/4\n\n/;t loopa
s/\n1\n9/9\n1\n/;t loopa
s/\n\n9/4\n1\n/;t loopa
s/\n1\n/5\n\n/;t loopa
s/\n\n\(.\)/\1\n\n/;t loopa
s/\n\n$//
H
g
s/.*, start/, start/
s/\n.*//
s/$/\n\n/
t loopb
:loopb
s/0\n1\n/\n\n1/;t loopb
s/0\n\n/\n\n0/;t loopb
s/1\n1\n/\n\n3/;t loopb
s/1\n\n/\n\n2/;t loopb
s/2\n1\n/\n\n5/;t loopb
s/2\n\n/\n\n4/;t loopb
s/3\n1\n/\n\n7/;t loopb
s/3\n\n/\n\n6/;t loopb
s/4\n1\n/\n\n9/;t loopb
s/4\n\n/\n\n8/;t loopb
s/5\n1\n/\n1\n1/;t loopb
s/5\n\n/\n1\n0/;t loopb
s/6\n1\n/\n1\n3/;t loopb
s/6\n\n/\n1\n2/;t loopb
s/7\n1\n/\n1\n5/;t loopb
s/7\n\n/\n1\n4/;t loopb
s/8\n1\n/\n1\n7/;t loopb
s/8\n\n/\n1\n6/;t loopb
s/9\n1\n/\n1\n9/;t loopb
s/9\n\n/\n1\n8/;t loopb
s/\n1\n/\n\n1/;t loopb
s/\(.\)\n\n/\n\n\1/;t loopb
s/^\n\n//
H
g
s/[^\n]*\n//
s/\n//
(在 awk 思想中要容易得多。)
注意:我曾经看到一个图灵机实现是 sed,所以我试着记住任何可以用编程语言完成的事情都可以在 sed 中完成。当然,这并不意味着 sed 在所有情况下都是好工具。
【讨论】:
\n。对于乘法,右边是解,中间是进位。
sed 中实现类似的算术循环时遇到了麻烦(为了挑战,而不是为了实际目的)。第一条t 指令似乎总是成功。 t 被定义为分支“如果自最近读取输入行或执行 t. 以来已经进行了任何替换”,在初始 s/$/\n\n/ 指令之后是正确的。因此,如果最后一位数字不是 0,则不会发生乘法运算。
Perl 在这里很有用:
perl -pe '
s{(\D+)(\d+)(\D+)(\d+)(\D+)(\d+)(\D+)(\d+)}
{$1 . $2/2 . $3 . $4/2 . $5 . $6*2 . $7 . $8*2}e
' file
如果您想就地编辑文件,perl 有一个 -i 选项,例如 sed。
【讨论】:
-i 选项,而不是相反。您不会在 sed 的 POSIX 规范的所需选项列表中找到 -i 选项,顺便说一句,而只是偶尔和非正式地在某些供应商端口中找到。阅读:sed -i 不被普遍支持,尽管perl -i 是。
不认为这是可能的。参见例如http://www.delorie.com/gnu/docs/sed/sed_15.html.
但是,如果您只有一小组可能的块、大小、开始和长度值,那么硬编码所需的替换可能是最快的。下一个最简单的选项可能是使用awk,但这不能就地修改文件。
【讨论】: