我在内容中有一个像这样的文件:
#INCLUDE<~/boulou/billy.txt>
从bash / sed脚本/命令中,我想用文件~/boulou/billy.txt
这是我当前可以找到文件路径的命令:
sed -E "s/#INCLUDE\<(.*)\>/\1/g" test.sh
这向我显示了文件路径,但是当我想用这个来获取内容时:
sed -E "s/#INCLUDE\<(.*)\>/$(cat \1)/g" test.sh
我收到错误消息“ cat:1:没有这样的文件或目录”
让我知道是否需要更多信息。
答案 0 :(得分:3)
您的代码不起作用,因为它首先运行cat \1
(与cat 1
相同),将输出插入sed命令,然后运行sed -E "s/...//g" test.sh
(空替换,因为cat 1
在stdout上不输出任何内容。
这是因为shell首先处理$( ... )
,然后运行生成的命令行。
对于您要执行的操作,您必须从搜索/替换命令内部读取文件,而不是从前读取。
我不知道如何用sed做到这一点,所以我只使用Perl:
perl -pe 's{#INCLUDE<([^<>]*)>}{ open my $fh, "<", $1 or die "$1: $!"; local $/; readline $fh }eg' test.sh
但是,这不适用于您的示例,因为~/boulou/billy.txt
不存在(您很可能在当前工作目录中没有一个名为~
的目录)。要解决此问题(并大大简化代码),我将使用:
perl -MPath::Tiny -pe 's{#INCLUDE<([^<>]*)>}{ path($1)->slurp }eg' test.sh
但是,这需要Path::Tiny
模块,它不是核心perl发行版的一部分。
可以手动扩展~
,但这会使代码更加混乱(这是我考虑将其放在单独的脚本文件中的地方):
perl -pe 's{#INCLUDE<([^<>]*)>}{ my $p = $1; $p =~ s{^~/}{$ENV{HOME}/}; open my $fh, "<", $p or die "$p: $!"; local $/; readline $fh }eg' test.sh
(免责声明:有些hacky,不处理~user
表示法,仅用~/
环境变量的内容替换前导HOME
。)
答案 1 :(得分:2)
您可以尝试类似的方法:
$ sed -r 's/#INCLUDE<(.*)>/printf "%b" "$(cat \1)"/e' test.sh
它应该工作得很流畅:)
答案 2 :(得分:1)
这可能对您有用(GNU sed):
sed 's/^#INCLUDE<\(.*\)>$/cat \1/e' file
这将计算替换命令右侧的表达式。在这种情况下,它将用<
和>
之间命名的文件内容替换匹配的行。
答案 3 :(得分:0)
这里的问题是外壳程序正在尽早替换$(cat \ 1)。也就是说,即使在执行sed命令并传递该参数之前,shell也会进行插值。
如果仅执行#INCLUDE替换,则可以考虑使用m4。如果您需要自己编写Awk,可能是解决此问题的一种合理方法。
答案 4 :(得分:0)
这将与在任何UNIX系统上的任何shell中运行任何awk的任何输入文件内容牢固地协同工作:
输入:
$ cat file1
before
foo [#INCLUDE<file2>] bar
after
$ cat file2
stuff
& nonsense
here
脚本:
$ cat tst.awk
match($0,/#INCLUDE<[^<>]*>/) {
file = substr($0,RSTART+9,RLENGTH-10)
rep = sep = ""
while ( (getline line < file) > 0 ) {
rep = rep sep line
sep = ORS
}
$0 = substr($0,1,RSTART-1) rep substr($0,RSTART+RLENGTH)
}
{ print }
输出:
$ awk -f tst.awk file1
before
foo [stuff
& nonsense
here] bar
after
the currently accepted answer将在相同的输入下执行以下操作:
$ sed -r 's/#INCLUDE<(.*)>/printf "%s" $(cat \1)/e' file1
before
/bin/sh: foo: command not found
after
这是如果INCLUDE自己一行的话会做的事情:
$ cat file1
before
#INCLUDE<file2>
after
$ sed -r 's/#INCLUDE<(.*)>/printf "%s" $(cat \1)/e' file1
before
stuff&nonsensehere
after
如果INCLUDE位于其自己的一行上,则此更简单的脚本将更接近于纠正:
$ sed -r 's/#INCLUDE<(.*)>/cat \1/e' file1
before
stuff
& nonsense
here
after
但是如果行上还有其他任何文本也会失败,因为它仍然会尝试执行它!