如何用 BASH 中的整个文件替换匹配项?
How to replace a match with an entire file in BASH?
我有这样一行:
输入文件 1
如何让 bash 读取该行并直接复制“file1.txt”的内容来代替该行?或者如果它看到: INPUT file2
在一行中,输入 `file2.txt" 等
我能做的最好的事情就是使用很多 tr
命令来将文件粘贴在一起,但这似乎是一个过于复杂的解决方案。
'sed'也是用字符串替换行,但是不知道怎么把一个文件的全部内容输入进去,替换成几百行。
awk
似乎非常简单。您可能希望优雅地处理错误 differently/more,但是:
$ cat file1
Line 1 of file 1
$ cat file2
Line 1 of file 2
$ cat input
This is some content
INPUT file1
This is more content
INPUT file2
This file does not exist
INPUT file3
$ awk '=="INPUT" {system("cat " ); next}1' input
This is some content
Line 1 of file 1
This is more content
Line 1 of file 2
This file does not exist
cat: file3: No such file or directory
如果您想在纯 Bash 中执行此操作,这里有一个示例:
#!/usr/bin/env bash
if (( $# < 1 )); then
echo "Usage: ${0##*/} FILE..."
exit 2
fi
for file; do
readarray -t lines < "${file}"
for line in "${lines[@]}"; do
if [[ "${line}" == "INPUT "* ]]; then
cat "${line#"INPUT "}"
continue
fi
echo "${line}"
done > "${file}"
done
保存到文件,然后 运行 像这样:./script.sh input.txt
(其中 input.txt
是一个包含混合了 INPUT <file>
语句的文本的文件)。
Perl 单行代码,使用 CPAN 模块 Path::Tiny
perl -MPath::Tiny -pe 's/INPUT (\w+)/path(".txt")->slurp/e' input_file
使用 perl -i -M...
就地编辑文件。
这不是最有效的方法,但作为练习,我制作了一个名为 x
的要编辑的文件和几个名为 t1
& t2
.[=16 的输入源=]
$: cat x
a
INPUT t2
b
INPUT t1
c
$: while read k f;do sed -ni "/$k $f/!p; /$k $f/r $f" x;done< <( grep INPUT x )
$: cat x
a
here's
==> t2
b
this
is
file ==> t1
c
是的,空白行在输入文件中。
不过,这将 sed
重复您的基础文件。
给出的 awk
解决方案更好,因为它只读了一次。
sed 类似于 awk 之前给定的解决方案:
$ cat f
test1
INPUT f1
test2
INPUT f2
test3
$ cat f1
new string 1
$ cat f2
new string 2
$ sed 's/INPUT \(.*\)/cat /e' f
test1
new string 1
test2
new string 2
test3
Bash 变体
while read -r line; do
[[ $line =~ INPUT.* ]] && { tmp=($BASH_REMATCH); cat ${tmp[1]}; } || echo $line
done < f
我有这样一行:
输入文件 1
如何让 bash 读取该行并直接复制“file1.txt”的内容来代替该行?或者如果它看到: INPUT file2
在一行中,输入 `file2.txt" 等
我能做的最好的事情就是使用很多 tr
命令来将文件粘贴在一起,但这似乎是一个过于复杂的解决方案。
'sed'也是用字符串替换行,但是不知道怎么把一个文件的全部内容输入进去,替换成几百行。
awk
似乎非常简单。您可能希望优雅地处理错误 differently/more,但是:
$ cat file1
Line 1 of file 1
$ cat file2
Line 1 of file 2
$ cat input
This is some content
INPUT file1
This is more content
INPUT file2
This file does not exist
INPUT file3
$ awk '=="INPUT" {system("cat " ); next}1' input
This is some content
Line 1 of file 1
This is more content
Line 1 of file 2
This file does not exist
cat: file3: No such file or directory
如果您想在纯 Bash 中执行此操作,这里有一个示例:
#!/usr/bin/env bash
if (( $# < 1 )); then
echo "Usage: ${0##*/} FILE..."
exit 2
fi
for file; do
readarray -t lines < "${file}"
for line in "${lines[@]}"; do
if [[ "${line}" == "INPUT "* ]]; then
cat "${line#"INPUT "}"
continue
fi
echo "${line}"
done > "${file}"
done
保存到文件,然后 运行 像这样:./script.sh input.txt
(其中 input.txt
是一个包含混合了 INPUT <file>
语句的文本的文件)。
Perl 单行代码,使用 CPAN 模块 Path::Tiny
perl -MPath::Tiny -pe 's/INPUT (\w+)/path(".txt")->slurp/e' input_file
使用 perl -i -M...
就地编辑文件。
这不是最有效的方法,但作为练习,我制作了一个名为 x
的要编辑的文件和几个名为 t1
& t2
.[=16 的输入源=]
$: cat x
a
INPUT t2
b
INPUT t1
c
$: while read k f;do sed -ni "/$k $f/!p; /$k $f/r $f" x;done< <( grep INPUT x )
$: cat x
a
here's
==> t2
b
this
is
file ==> t1
c
是的,空白行在输入文件中。
不过,这将 sed
重复您的基础文件。
给出的 awk
解决方案更好,因为它只读了一次。
sed 类似于 awk 之前给定的解决方案:
$ cat f
test1
INPUT f1
test2
INPUT f2
test3
$ cat f1
new string 1
$ cat f2
new string 2
$ sed 's/INPUT \(.*\)/cat /e' f
test1
new string 1
test2
new string 2
test3
Bash 变体
while read -r line; do
[[ $line =~ INPUT.* ]] && { tmp=($BASH_REMATCH); cat ${tmp[1]}; } || echo $line
done < f