例如,一个temp.txt
文件包含如下信息:
adsf on line jhkjhvjdbvjvbvbdjkvn
qerwtt on line fdgdgdgdd
qwqertg on line safffasffaf
wrt on line adaddsd
我想on line
在文件的所有行中进行 grep 并将行的剩余部分写入另一个文件,即在temp.txt
文件处理之后,新文件应包含:
on line jhkjhvjdbvjvbvbdjkvn
on line fdgdgdgdd
on line safffasffaf
on line adaddsd
我怎样才能在Linux终端中做到这一点?
答案1
使用-o
的选项grep
仅选择所需的部分,在您的情况下,使用模式on line .*
选择从on line
行开始到行尾的部分:
% grep -o 'on line .*' temp.txt >new.txt
% cat new.txt
on line jhkjhvjdbvjvbvbdjkvn
on line fdgdgdgdd
on line safffasffaf
on line adaddsd
答案2
鉴于vi
这个问题的标签,以及我发现自动文件编辑的事实符合 POSIX 标准的ex
命令sed
与、awk
、grep
甚至 Perl上的大量建议相比,此站点上的建议很冷淡,这里有一个 POSIX 兼容的ex
命令,它将执行所需的过滤:
ex -sc 'g/.*\(on line\)/s//\1/ | .w!>>output
q!' input
注意命令中嵌入的换行符——这对于完整的 POSIX 可移植性是必要的,因为没有其他明确的方法来结束g
lobal 命令;然而最多实现允许多个-c
命令,在这种情况下,以下一个衬垫将同样工作:
ex -sc 'g/.*\(on line\)/s//\1/ | .w!>>output' -c 'q!' input
ex
该命令中包含一些正则表达式魔法和大量-command 魔法,并且由于ex
似乎不是很广为人知,因此我将解释每个部分:
-s
以静默模式启动ex
,“准备批处理”,因此没有任何内容输出到您的终端。
-c
意思是“打开文件时运行以下命令。” (input
是要打开的文件的名称。)
该ex
命令本身实际上是两个命令:
g/.*\(on line\)/s//\1/ | .w!>>output
q!
g
是“全局”命令,意味着“在与指定正则表达式匹配的文件的所有行上运行以下命令(该行的其余部分)”。
给出的正则表达式是.*\(on line\)
,这意味着“任意次数的任何字符,包括 0,后跟“on line””。括号用于捕获“在线”以便稍后反向引用。
事实上,g
命令本身也可以是这样,g/on line/
而且它的工作原理是一样的。但是,s
我编写的替代命令使用没有什么对于它的正则表达式s//
——这意味着“重用上次使用的正则表达式”。然后该s
命令用于\1
替换文本,在本例中表示“在线”。
|
命令中的管道符号ex
并不像 shell 中那样表示管道。相反,它是通常用于分隔单独的ex
命令,每个命令按顺序但独立运行。然而,g
lobal 命令是一个例外:在全局命令中,竖线将所有命令分隔开。之内全局命令——即只运行此类命令在与正则表达式匹配的行上在全局命令中指定。
在这种情况下,竖线后面的命令是w
仪式命令。它前面有一个点,.
指定“当前行”;如果没有这个地址说明符,写命令将写入全部的文件,无论当前行是什么。 (由于我们在全局命令中使用 write 命令,因此如果我们省略点,则 write 命令将在每个匹配行已对其执行了替换命令!)
这>>
意味着“如果文件已经存在,则追加到它而不是给出错误”。由于我们多次写入文件,这是必要的,否则我们最终只会得到最后的写入输出文件的行。前面!
的>>
意思是“如果文件不如果已经存在,请创建该文件并写入它,而不是抛出错误。”(如果没有,!
POSIX 中未指定是否会发生这种情况。)当然还有output
要写入的文件的名称。
最后,当然,q!
意味着“退出而不保存对当前文件的更改”。我们已经对文件的许多行进行了替换input
,但我们不想保存这些更改,因此我们使用q!
.
还有一些其他等效的方法,例如以下:
ex -sc '%s/.*\(on line\)/\1/e | v//d
w output | q!' input
但这使用了e
替代命令的标志,而 POSIX 中没有该标志。 (如果省略此标志,则当.*\(on line\)
在文件中的任何位置都找不到正则表达式时,批处理将停止。)
当然,哪里ex
真的闪耀是在到位文件编辑。但它当然可以用于将一个文件过滤到另一个文件,如上所示。
答案3
尝试这个:
grep -o 'on line .*' temp.txt > out.txt
该-o
参数使 grep 只输出该行的匹配部分,这就是你想要的。
答案4
如果您grep
不支持该-o
选项:
sed 's/^.*\(on line\)/\1/' temp.text > out.txt
或者,如果您只想要包含以下内容的行on line
:
sed -n 's/^.*\(on line\)/\1/p' temp.text > out.txt
请注意,如果 多次出现on line
,它将打印以 开头的行部分最右边的它的发生。对于最左边的出现:
sed '/on line/!d;s//\
&/;s/.*\n//' temp.text > out.txt