use*_*191 48 sed awk perl text-processing
File1 内容:
line1-file1 "1"
line2-file1 "2"
line3-file1 "3"
line4-file1 "4"
Run Code Online (Sandbox Code Playgroud)
File2 内容:
line1-file2 "25"
line2-file2 "24"
Pointer-file2 "23"
line4-file2 "22"
line5-file2 "21"
Run Code Online (Sandbox Code Playgroud)
perl/shell脚本执行后,File2内容应该变成:
line1-file2 "25"
line2-file2 "24"
line1-file1 "1"
line2-file1 "2"
line3-file1 "3"
line4-file1 "4"
Pointer-file2 "23"
line4-file2 "22"
line5-file2 "21"
Run Code Online (Sandbox Code Playgroud)
即File1在File2包含“指针”的行之前粘贴in的内容。
jfg*_*956 55
sed 有一个功能,可以就地进行修改:
sed -i -e '/Pointer/r file1' file2
Run Code Online (Sandbox Code Playgroud)
但这会将您的指针行置于 file1 之上。把它放在下面,延迟线输出:
sed -n -i -e '/Pointer/r file1' -e 1x -e '2,${x;p}' -e '${x;p}' file2
Run Code Online (Sandbox Code Playgroud)
sed '/Pointer/e cat file1' file2
Run Code Online (Sandbox Code Playgroud)
按照说明书的e [command]
请注意,与 r 命令不同,该命令的输出将立即打印;r 命令将输出延迟到当前周期结束。
jfg*_*956 22
不使用sed或awk。
首先,找到您的模式所在的行:
line=$(grep -n 'Pointer' file2 | cut -d ":" -f 1)
Run Code Online (Sandbox Code Playgroud)
然后,使用 3 个命令输出想要的结果:
{ head -n $(($line-1)) file2; cat file1; tail -n +$line file2; } > new_file
Run Code Online (Sandbox Code Playgroud)
这有访问3次的缺点file2,但可能比一个更清晰sed的awk解决方案。
Kev*_*vin 13
awk使这相当容易。
在文件前插入一行:
awk '/Pointer/{while(getline line<"innerfile"){print line}} //' outerfile >tmp
mv tmp outerfile
Run Code Online (Sandbox Code Playgroud)
要使内部文件打印Pointer在行后,只需切换模式的顺序(您需要添加分号以获得默认操作),您可以删除line变量:
awk '//; /Pointer/{while(getline<"innerfile"){print}}' outerfile >tmp
mv tmp outerfile
Run Code Online (Sandbox Code Playgroud)
只是因为还没有人用过perl,
# insert file before line
perl -e 'while(<>){if($_=~/Pointer/){system("cat innerfile")};print}' outerfile
# after line
perl -e 'while(<>){print;if($_=~/Pointer/){system("cat innerfile")}}' outerfile
Run Code Online (Sandbox Code Playgroud)
一个简单的工作ed:
ed -s file1 <<IN
/Pointer/-r file2
,p
q
IN
Run Code Online (Sandbox Code Playgroud)
-r file1读入指定文件到寻址行之后,在本例中是匹配 的第一行之前的行Pointer。因此,file2即使Pointer出现在多行上,这也只会插入一次内容。如果要在每个匹配行之前插入它,请添加global 标志:
ed -s file1 <<IN
g/Pointer/-r file2
,p
q
IN
Run Code Online (Sandbox Code Playgroud)
更换,p用w,如果你要编辑就地文件。
接受的sed答案在大多数情况下确实有效,但如果标记在最后一行,则该命令将无法按预期工作:它将File1在标记之后插入 的内容。
我最初尝试过:
sed '/Pointer/{r file1
N}' file2
Run Code Online (Sandbox Code Playgroud)
这也可以正常工作(r在循环结束时会发挥其魔力)但如果标记位于最后一行(最后N一行之后没有ext 行),则会出现相同的问题。要解决此问题,您可以在输入中添加换行符:
sed '/Pointer/{ # like the first one, but this time even if the
r file1 # marker is on the last line in File2 it
N # will be on the second to last line in
} # the combined input so N will always work;
${ # on the last line of input: if the line is
/^$/!{ # not empty, it means the marker was on the last
s/\n$// # line in File2 so the final empty line in the
} # input was pulled i\n: remove the latter;
//d # if the line is empty, delete it
}' file2 <(printf %s\\n)
Run Code Online (Sandbox Code Playgroud)
这将file2在每个匹配行之前插入内容。要仅在第一个匹配行之前插入它,您可以使用loop 并在next 行中拉入,直到到达文件末尾:
sed '/Pointer/{
r file2
N
:l
$!n
$!bl
}
${
/^$/!{
s/\n$//
}
//d
}' file1 <(printf %s\\n)
Run Code Online (Sandbox Code Playgroud)
使用这些sed解决方案,您将无法就地编辑(但您可以重定向到另一个文件)。
使用循环读取 file2 中的行。如果找到以 开头的行Pointer,则打印出 file1。这如下所示:
#!/bin/bash
while IFS= read -r line
do
if [[ "$line" =~ ^Pointer.*$ ]]
then
cat file1
fi
echo "$line"
done < file2
Run Code Online (Sandbox Code Playgroud)
小智 8
[将文件内容插入到另一个文件中 BEFORE 模式]
sed -i '/PATTERN/r file1' -e //N file2
Run Code Online (Sandbox Code Playgroud)
[图案后]
sed -i '/PATTERN/r file1' file2
Run Code Online (Sandbox Code Playgroud)
有几种方法可以解决这个问题sed。一种方法是延迟阅读,如已接受的答案中所建议的那样。也可以写成:
sed -e '$!N;P;/\nPointer/r file1' -e D file2
Run Code Online (Sandbox Code Playgroud)
...带有一点明确的前瞻,而不是在其他地方使用保持缓冲区实现的后视。但是,@don_crissti 指出的最后一行不可避免地会出现相同的问题,因为N 确实会增加行周期,并且read 命令是按行号应用的。
你可以绕过它:
echo | sed -e '$d;N;P;/\nPointer/r file1' -e D file2 -
Run Code Online (Sandbox Code Playgroud)
并非所有seds 都会将 the 解释-为表示标准输入,但许多会解释。(POSIX 说 如果实现者想要表示标准输入,sed应该支持表示标准输入???)--
另一种方法是按顺序处理附加的内容。还有另一个命令以与ead相同的方式安排输出r,并将按照脚本编写的顺序sed应用它和read。不过它有点复杂 - 它需要使用一个sed来a将Pointer匹配项附加到sed其脚本中另一个的输出。
sed ' /Pointer/!d #only operate on first match
s/[]^$&\./*[]/\\&/g;H #escape all metachars, Hold
s|.*|/&/!p;//!d|p;g #print commands, exchange
s|.|r file1&a\\&|;q' file2| #more commands, quit
sed -nf - file2 #same input file
Run Code Online (Sandbox Code Playgroud)
所以基本上第一个sed写第二sed个脚本,第二个sed在标准输入(也许......)上读取并依次应用。第一个sed仅适用于Pointer找到的第一个匹配项,然后是quits 输入。它的工作是...
s/[]^$&\./*[]/\\&/g;H
sed将需要逐字解释它读取的每一位以使其正确。完成后,将副本放入H旧空间。s|.*|/&/!p;//!d|p; x
sed至pRINT每个输入线!,但/&/一个我们刚刚图案萨法德; 然后d删除所有相同的内容。p在第二个 rint 命令sed,然后x更改h旧缓冲区和模式缓冲区以处理我们保存的副本。s|.|r file1&a\\&|p;q
\newline,因为sed在我们H之前设置该行时会预先添加一个字符。所以我们插入命令r file1并在它后面加上我们的\newline,然后是ppend命令a\\,a然后是一个\newline。我们Held 线的所有其余部分都遵循最后一条\newline。第一个编写的脚本如下所示:
/Pointer-file2 "23"/!p;//!d
r file1
a\
Pointer-file2 "23"
Run Code Online (Sandbox Code Playgroud)
基本上,第二个sed将打印每一行,但第一个sed将其设置为append。对于特定的行2延迟写入到标准输出的计划-首先是r的EAD file1,第二个是我们之后要行的副本。sed在这种情况下,第一个的篡改甚至没有必要(看到了吗?没有反斜杠),但是每当模式匹配被重新用作输入时,以我在这里所做的方式安全地转义很重要。
无论如何,所以......有几种方法。