用文件的内容替换某些标记(使用 bash 脚本)

Posted

技术标签:

【中文标题】用文件的内容替换某些标记(使用 bash 脚本)【英文标题】:Replace certain token with the content of a file (using a bash-script) 【发布时间】:2011-05-21 17:19:24 【问题描述】:

我有一个文件,其中包含一些文本和单词INSERT_HERE1INSERT_HERE2。我想分别用file1.txtfile2.txt的内容来替换这些词。

我怀疑sedawk 可以成功,但我基本上从未使用过它们。

【问题讨论】:

【参考方案1】:

Sed 确实有一个内置的读取文件命令。你想要的命令看起来像这样:

$ sed -e '/INSERT_HERE1/ 
r FILE1
d ' -e '/INSERT_HERE2/ 
r FILE2
d ' < file

这会输出

foo
this is file1
bar
this is file2
baz

r 命令读取文件,d 命令删除带有INSERT_HERE 标记的行。您需要使用花括号,因为 sed 命令和多行输入,因为 sed 命令必须从自己的行开始,并且根据您的 shell,您可能需要在行尾使用 \ 以避免过早执行。如果这是你经常使用的东西,你可以把命令放在一个文件中,然后使用sed -f 来运行它。

【讨论】:

hm,这似乎只适用于 INSERT_HERE1 和 INSERT_HERE2 作为单行上的单个单词,否则整行文本将被替换?【参考方案2】:

如果你对 Perl 没问题,你可以这样做:

$ cat FILE1
this is file1

$ cat FILE2
this is file2

$ cat file
foo
INSERT_HERE1
bar
INSERT_HERE2
baz

$ perl -ne 's/^INSERT_HERE(\d+)\s+$/`cat FILE$1`/e;print' file
foo
this is file1
bar
this is file2
baz
$ 

【讨论】:

嗯.. 我想降低依赖关系。 perl 是否像 sed 一样普遍安装? @aioobe 是的。我不知道任何不包含 Perl 的现代 Unix 系统。 @aioobe 是的。 Perl 无处不在。【参考方案3】:

这未经测试,但与您需要的非常接近:

sed -e "s/INSERT_HERE1/`cat file1.txt`/" -e "s/INSERT_HERE2/`cat file2.txt`/" <file >file.out

不过,它不能正确处理带有斜杠的文件,因此您可能需要稍微调整一下。

不过,我会推荐 Perl。像这样的:

#!/usr/bin/perl -w

my $f1 = `cat file1.txt`;
my $f2 = `cat file2.txt`;

while (<>) 
    chomp;
    s/INSERT_HERE1/$f1/;
    s/INSERT_HERE2/$f2/;
    print "$_\n";

这假设 INSERT_HERE1 和 INSERT_HERE2 每行可能只出现一次,并且file1.txt 不包含文本 INSERT_HERE2(虽然不难修复)。像这样使用:

./script <file >file.out

【讨论】:

哦,当然。我想使用 perl,但我要让其他人使用这个脚本,所以我想降低依赖关系。我会试试你的 sed-line! 嗯.. sed 行似乎不起作用。可能是因为file1.txt包含'等字符。 我认为不可能在sed 中做到这一点并允许输入文件包含任何字符。不幸的是,我不知道awk,所以我不能说那里是否有更好的解决方案。 sed 是标准而 perl 不是标准的,你在哪种系统上?【参考方案4】:

这适用于可能被多次替换的小替换文件:

awk 'BEGIN 
        while ((getline line < ARGV[1]) > 0) file1 = file1 nl line; nl = "\n"; 
        close (ARGV[1]); nl = "";
        while ((getline line < ARGV[2]) > 0) file2 = file2 nl line; nl = "\n";
        close (ARGV[2]);
        ARGV[1] = ""; ARGV[2] = "" 
       gsub("token1", file1); 
        gsub("token2", file2); 
        print ' file1.txt file2.txt mainfile.txt

您可能希望在这里和那里添加一些额外的换行符,具体取决于您希望输出的外观。

【讨论】:

我会将文件内容作为变量传递:awk -v "f1=$(&lt; file1)" -v "f2=$(&lt; file2)" 'gsub(... @glenn:这是另一种方法。我展示的方式可以很容易地将文件名作为参数传递,并允许在读取期间进行一些预处理,如果需要的话。【参考方案5】:

使用 Bash 轻松完成。如果您需要它是 POSIX shell,请告诉我:

#!/bin/bash

IFS=  # Needed to prevent the shell from interpreting the newlines
f1=$(< /path/to/file1.txt)
f2=$(< /path/to/file2.txt)

while read line; do 
  if [[ "$line" == "INSERT_HERE1" ]]; then
     echo "$f1"
  elif [[ "$line" == "INSERT_HERE2" ]]; then
     echo "$f2"
  else
     echo "$line"
  fi
done < /path/to/input/file

【讨论】:

【参考方案6】:

这个 sn-p 替换了上面数组中指定的任何部分。例如这里

<!--insert.txt-->

带有“insert.txt”的内容

#!/bin/bash

replace[1]=\<!--insert.txt--\>      ; file[1]=insert.txt
replace[2]=\<!--insert2.txt--\>     ; file[2]=insert2.txt

replacelength=$#replace[@]

cat blank.txt > tmp.txt
for i in $(seq 1 $replacelength)
do
    echo Replacing $file[i] ...
    sed -e "/$replace[i]/r $file[i]" -e "/$replace[i]/d" tmp.txt > tmp_2.txt
    mv tmp_2.txt tmp.txt
done
mv tmp.txt file.txt

如果你不怕 .zip 文件,只要在线就可以试试这个例子:http://ablage.stabentheiner.de/2013-04-16_contentreplace.zip

【讨论】:

【参考方案7】:

我会用-i.ext 选项替换perl

perl -pi.bak -e 's|INSERT_HERE1|`cat FILE1`|ge; 
                 s|INSERT_HERE2|`cat FILE2`|ge;' myfile

然后,使用diff myfile.bak myfile进行验证:

【讨论】:

以上是关于用文件的内容替换某些标记(使用 bash 脚本)的主要内容,如果未能解决你的问题,请参考以下文章

用脚本中的 sed 将行替换为文件的内容

bash 脚本在 y 出现时找到计数高于 x 的行,然后用 z 替换某个点之后的任何内容

用 Bash 脚本中的 sed 替换文件中的版本号

如何使用 bash 脚本替换文件名中的空格

在 bash 脚本中使用 sed 替换多行模式

用bash中的另一个文件替换整个文件