我正在尝试编写一个bash脚本,它将执行以下操作:
例如:
first_file.txt:
111111
1111
11
1
second_file.txt:
122221
2222
22
2
图案:
2222
输出:
122221
111111
1111
11
1
2222
111111
1111
11
1
22
2
我应该使用什么来实现BASH上的这项功能?
我编写了代码,但它无法正常工作(为什么?):
#!/bin/bash
first_filename="$1"
second_filename="$2"
pattern="$3"
while read -r line
do
if [[ $line=˜$pattern ]]; then
while read -r line2
do
echo $line2
done < $second_filename
fi
echo $line
done < $first_filename
答案 0 :(得分:30)
sed
可以在没有循环的情况下做到这一点。使用其r
命令:
sed -e '/pattern/rFILE1' FILE2
测试环节:
$ cd -- "$(mktemp -d)"
$ printf '%s\n' 'nuts' 'bolts' > first_file.txt
$ printf '%s\n' 'foo' 'bar' 'baz' > second_file.txt
$ sed -e '/bar/r./first_file.txt' second_file.txt
foo
bar
nuts
bolts
baz
答案 1 :(得分:6)
使用 awk 也可以。
要在###标记###行之前插入:
// for each <line> of second_file.txt :
// if <line> matches regexp ###marker###, outputs first_file.txt.
// **without any condition :** print <line>
awk '/###marker###/ { system ( "cat first_file.txt" ) } \
{ print; } \' second_file.txt
在### marker ### line:
之后插入// for each <line> of second_file.txt :
// **without any condition :** print <line>
// if <line> matches regexp ###marker###, outputs first_file.txt.
awk '{ print; } \
/###marker###/ { system ( "cat first_file.txt" ) } \' second_file.txt
替换### marker ### line:
// for each <line> of second_file.txt :
// if <line> matches regexp ###marker###, outputs first_file.txt.
// **else**, print <line>
awk '/###marker###/ { system ( "cat first_file.txt" ) } \
!/###marker###/ { print; }' second_file.txt
如果要进行就地替换,请使用临时文件以确保在awk读取整个文件之前管道未启动;添加:
> second_file.txt.new
mv second_file.txt{.new,}
// (like "mv second_file.txt.new second_file.txt", but shorter to type !)
如果您想在线内更换(仅替换模式并保留线的其余部分),则应使用 sed 来实现类似的解决方案,而不是的 AWK 强>
答案 2 :(得分:2)
我像这样使用sed,它可以作为魅力
sed -i -e&#39; / pattern / r filetoinsert&#39; filetobeinserted 强>
它的作用是插入&#39; filetoinsert&#39;进入&#39; filetobeinserted&#39;在具有指定模式的行
之后注意选择一个独特的模式,不确定它如何与重复的模式一起使用,我认为它只会在第一个模式中使用
答案 3 :(得分:1)
=~
运算符周围需要空格。比较:
[[ foo=~bar ]]
[[ foo =~ bar ]]
这是因为第一个表达式基本上评估为“这个字符串是空的吗?”
此外, OP代码使用small tilde而不是tilde 。
即便如此,你也可以轻松摆脱内循环。只需将整个while read -r line2
位替换为cat -- "$second_filename"
。
如果文件不以换行符(使用* nix工具标准)结束,则您的上一个echo $line
才有效。相反,您应该使用while read -r line || [[ $line ~= '' ]]
。这最终有或没有换行。
另外,Use More Quotes™。
答案 4 :(得分:1)
这应该有效:
perl -lne 'BEGIN{open(A,"first_file.txt");@f=<A>;}print;if(/2222/){print @f}' second_file.txt
测试:
> cat temp
111111
1111
11
1
> cat temp2
122221
2222
22
2
> perl -lne 'BEGIN{open(A,"temp");@f=<A>;}print;if(/2222/){print @f}' temp2
122221
111111
1111
11
1
2222
111111
1111
11
1
22
2
>