18

我想将匹配特定模式的行从file1移动到file2。类似于在 windows 中从一个文件剪切和粘贴到另一个文件的操作

例子

假设我想barfile1中剪切所有包含的行并将其粘贴到新创建的file2中

输入:

文件 1

bla foo bla
bla bar bla
bla aaa bla
bla bar bla
bla foo bla

处理后所需的输出:

文件 1

bla foo bla
bla aaa bla
bla foo bla

文件2

bla bar bla
bla bar bla

我试过的

grep创建所需的file2但不修改file1

grep 'bar' file1 > file2

sed -i修改所需的file1但不创建file2

sed -i '/bar/d' file1

如果我一个接一个地执行这两个命令,我会得到想要的结果。但是在这里我出于好奇而寻找单行命令并使脚本更简洁。

您的帮助将不胜感激。

4

5 回答 5

17

这可能对您有用(GNU sed):

sed -i -e '/bar/{w file2' -e 'd}' file1

替代:

sed -i -e '/bar/w file2' -e '//d' file1

要追加到 file2,写入临时文件并使用 cat 在 bash 脚本中追加到文件末尾,或使用:

sed -i -e '/bar/w tmpfile' -e '$e cat tmpfile >> file2 && rm tmpfile' -e '//d' file1

注意对于最后一种解决方案,一次只能修改一个输入文件。

于 2013-10-19T20:30:11.340 回答
5

您可以使用并在打印时根据正则表达式的匹配选择不同的文件句柄:

perl -i.bak -ne 'BEGIN { open $oh, q|>|, pop or die } { print { m/bar/ ? $oh : q|ARGVOUT| } $_ }' file1 file2

它产生:

==> file1 <==
bla foo bla
bla aaa bla
bla foo bla

==> file2 <==
bla bar bla
bla bar bla
于 2013-10-19T10:59:06.027 回答
3

这个awk脚本可以解决问题:

awk '{a[NR]=$0}END{for(i=1;i<=NR;i++)print a[i] > "file"(a[i]~/bar/?2:1)}' file1

输出:

$ cat file1
bla foo bla
bla aaa bla
bla foo bla

$ cat file2
bla bar bla
bla bar bla
于 2013-10-19T11:26:32.953 回答
1

您可以&&在两个命令之间放置 a 以使它们成为单行。但这不会更具可读性,所以我不建议你这样做。

要在一个命令中执行相同的操作,您需要能够就地编辑文件、删除不需要的行并同时将这些行打印到stdout或者stderr您可以将其重定向到另一个文件的东西。也许ed可以做到这一点,但我不知道怎么写。我认为没有其他“标准”UNIX 工具可以做到这一点。

顺便说一句,剪切和粘贴实际上有 3 个步骤:

  1. 将所选文本复制到剪贴板
  2. 从原始文件中删除
  3. 从剪贴板粘贴到新文件

两步 UNIX 命令在没有剪贴板的情况下执行此操作。

于 2013-10-19T10:53:01.440 回答
0

我喜欢其他答案,但只是一种(明显的)替代方法,以防您担心在您的模式中犯错误并想要一种简单的回滚方法:

grep    'bar' file1 > file2
grep -v 'bar' file1 > file3

一旦您对结果感到满意(提示:tee而不是>让您查看写入文件的内容):

mv file3 file1

一般来说,我更喜欢 perl 像上面的答案那样做替换,但是当正则表达式变得太复杂并且你半盲地复制和粘贴你不理解的命令时,你就无法控制你的宝贵数据。

于 2016-11-14T20:37:26.193 回答