假设我有一个文件,Foo.in
:
Contents of Foo
和Bar.in
INSERT Foo.in
Contents of Bar
我想编写一个sed
脚本,将INSERT xyz
替换为xyz
文件的实际内容。在这个特定示例中,我想生成包含以下内容Bar.out
文件:
Contents of Foo
Contents of Bar
我想过使用 sed
的 r
命令,如这个堆栈 溢出问题所示,但问题是要插入的文件的名称是在文件本身中指定的。我想过扫描文件中的INSERT
命令,然后为每个找到的INSERT
分别运行sed
,但这是一个具有 O(n^2) 复杂性的可怕解决方案。我更喜欢使用 sed 或 AWK 来做到这一点,但如果所有其他方法都失败了,Perl 脚本是可以接受的。
$ cat Foo.in
Contents of Foo
$ cat Bar.in
INSERT Foo.in
Contents of Bar.in
$ awk '/INSERT/{while((getline line < $2) > 0 ){print line}close($2);next}1' Bar.in
Contents of Foo
Contents of Bar.in
这很容易做到。下面是一个小的 Perl 脚本:
#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
while(<>) {
# If this line is an INSERT command, capture the filename and insert it
if (my ($filename) = /^INSERTs+(.+)$/) {
open my $fh, "<", $filename;
local $/;
print <$fh>;
}
# Otherwise just print out the line as it is.
else {
print;
}
}
用法:$ perl the-script.pl some_file.txt > output.txt
此解决方案存在一些问题:不会处理插入文件中的INSERT
。INSERT
中的文件路径是相对于调用的工作目录而不是相对于发出INSERT
的文件进行解释的。
阿蒙使用你的正则表达式,
perl -MFile::Slurp -pe '$_= read_file($1) if /^INSERTs+(.+)$/' file
递归
$ cat Foo.in
Contents of Foo
INSERT test
$ cat test
1
2
3
4
5
$ cat Bar.in
INSERT Foo.in
Contents of Bar.in
AWK 代码:
awk '
function fetch(inp){
while( (getline p < inp) > 0)
print p
close(inp)
}
/INSERT/{
while((getline line < $2) > 0)
{
if(line ~ /INSERT/){
split(line,A)
fetch(A[2])
next
}
else{
print
}
}
close($2)
next
}1
' Bar.in
结果:
INSERT Foo.in
1
2
3
4
5
Contents of Bar.in
---编辑---
$ cat test.awk
function fetch(inp){
while( (getline p < inp) > 0)
print p
close(inp)
}
/INSERT/{
while((getline line < $2) > 0)
{
if(line ~ /INSERT/){
split(line,A)
fetch(A[2])
next
}
else{
print
}
}
close($2)
next
}1
用法:
$ awk -f test.awk Bar.in
你也可以在不加载Perl模块的情况下做到这一点,字符更少:
perl -pe 'open $F,"<$1" and $_=<$F> if /^INSERTs+(.+)$/' [file]