使用sed或awk删除行
我有一个像这样的data.txt文件使用sed或awk删除行,sed,awk,Sed,Awk,我有一个像这样的data.txt文件 >1BN5.txt 207 208 211 >1B24.txt 88 92 我有一个文件夹F1,其中包含文本文件 F1文件夹中的1BN5.txt文件如下所示 ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.7
>1BN5.txt
207
208
211
>1B24.txt
88
92
我有一个文件夹F1,其中包含文本文件
F1文件夹中的1BN5.txt文件如下所示
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 422 C SER A 248 70.124 -29.955 8.226 1.00 55.81 C
ATOM 615 H LEU B 208 3.361 -5.394 -6.021 1.00 10.00 H
ATOM 616 HA LEU B 211 2.930 -4.494 -3.302 1.00 10.00 H
ATOM 626 N MET B 87 1.054 -3.071 -5.633 1.00 10.00 N
ATOM 627 CA MET B 87 -0.213 -2.354 -5.826 1.00 10.00 C
ATOM 630 CB MET B 87 -0.476 -2.140 -7.318 1.00 10.00 C
ATOM 631 CG MET B 88 -0.828 -0.688 -7.575 1.00 10.00 C
ATOM 632 SD MET B 88 -2.380 -0.156 -6.830 1.00 10.00 S
ATOM 643 N ALA B 92 -1.541 -4.371 -5.366 1.00 10.00 N
ATOM 644 CA ALA B 94 -2.560 -5.149 -4.675 1.00 10.00 C
F1文件夹中的1B24.txt文件如下所示
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 422 C SER A 248 70.124 -29.955 8.226 1.00 55.81 C
ATOM 615 H LEU B 208 3.361 -5.394 -6.021 1.00 10.00 H
ATOM 616 HA LEU B 211 2.930 -4.494 -3.302 1.00 10.00 H
ATOM 626 N MET B 87 1.054 -3.071 -5.633 1.00 10.00 N
ATOM 627 CA MET B 87 -0.213 -2.354 -5.826 1.00 10.00 C
ATOM 630 CB MET B 87 -0.476 -2.140 -7.318 1.00 10.00 C
ATOM 631 CG MET B 88 -0.828 -0.688 -7.575 1.00 10.00 C
ATOM 632 SD MET B 88 -2.380 -0.156 -6.830 1.00 10.00 S
ATOM 643 N ALA B 92 -1.541 -4.371 -5.366 1.00 10.00 N
ATOM 644 CA ALA B 94 -2.560 -5.149 -4.675 1.00 10.00 C
我只需要1BN5.txt文件中包含207208211(第6列)的行。我想删除1BN5.txt文件中的其他行。像这样,我只需要1B24.txt文件中包含88,92的行
Desired output
1BN5.txt文件
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 615 H LEU B 208 3.361 -5.394 -6.021 1.00 10.00 H
ATOM 616 HA LEU B 211 2.930 -4.494 -3.302 1.00 10.00 H
1B24.txt文件
ATOM 631 CG MET B 88 -0.828 -0.688 -7.575 1.00 10.00 C
ATOM 632 SD MET B 88 -2.380 -0.156 -6.830 1.00 10.00 S
ATOM 643 N ALA B 92 -1.541 -4.371 -5.366 1.00 10.00 N
不要尝试从现有文件中删除行,请尝试创建一个新文件,其中只包含您想要的行:
cat 1bn5.txt | awk '$6 == 207 || $6 == 208 || $6 == 211 { print }' > output.txt
肯定是awk的工作:
$ awk '$6==207||$6==208||$6==211 { print }' 1bn5.txt
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 615 H LEU B 208 3.361 -5.394 -6.021 1.00 10.00 H
ATOM 616 HA LEU B 211 2.930 -4.494 -3.302 1.00 10.00 H
$ awk '$6==92||$6==88 { print }' 1B24.txt
ATOM 631 CG MET B 88 -0.828 -0.688 -7.575 1.00 10.00 C
ATOM 632 SD MET B 88 -2.380 -0.156 -6.830 1.00 10.00 S
ATOM 643 N ALA B 92 -1.541 -4.371 -5.366 1.00 10.00 N
/^>/ {
file = substr($1,2)
next
}
{
a[file][$1]
}
END {
for (i in a) {
while ( ( getline line < ("./F1/" i) ) > 0 ) {
split(line,b)
for (j in a[i]) {
if (b[6]==j) {
print line > "./F1/" i ".new"
}
}
}
system(sprintf("mv ./F1/%s.new ./F1/%s", i, i))
}
}
重定向以保存输出:
$ awk '$6==207||$6==208||$6==211 { print }' 1bn5.txt > output.txt
这里有一种使用
GNU awk
的方法。运行方式如下:
awk -f script.awk data.txt
awk -f script.awk data.txt
script.awk的内容
:
$ awk '$6==207||$6==208||$6==211 { print }' 1bn5.txt
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 615 H LEU B 208 3.361 -5.394 -6.021 1.00 10.00 H
ATOM 616 HA LEU B 211 2.930 -4.494 -3.302 1.00 10.00 H
$ awk '$6==92||$6==88 { print }' 1B24.txt
ATOM 631 CG MET B 88 -0.828 -0.688 -7.575 1.00 10.00 C
ATOM 632 SD MET B 88 -2.380 -0.156 -6.830 1.00 10.00 S
ATOM 643 N ALA B 92 -1.541 -4.371 -5.366 1.00 10.00 N
/^>/ {
file = substr($1,2)
next
}
{
a[file][$1]
}
END {
for (i in a) {
while ( ( getline line < ("./F1/" i) ) > 0 ) {
split(line,b)
for (j in a[i]) {
if (b[6]==j) {
print line > "./F1/" i ".new"
}
}
}
system(sprintf("mv ./F1/%s.new ./F1/%s", i, i))
}
}
script.awk的内容:
/^>/ {
file = substr($1,2)
next
}
{
a[file]=( a[file] ? a[file] SUBSEP : "") $1
}
END {
for (i in a) {
split(a[i],b,SUBSEP)
while ( ( getline line < ("./F1/" i) ) > 0 ) {
split(line,c)
for (j in b) {
if (c[6]==b[j]) {
print line > "./F1/" i ".new"
}
}
}
system(sprintf("mv ./F1/%s.new ./F1/%s", i, i))
}
}
F1/1B24.txt的内容
:
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 615 H LEU B 208 3.361 -5.394 -6.021 1.00 10.00 H
ATOM 616 HA LEU B 211 2.930 -4.494 -3.302 1.00 10.00 H
ATOM 631 CG MET B 88 -0.828 -0.688 -7.575 1.00 10.00 C
ATOM 632 SD MET B 88 -2.380 -0.156 -6.830 1.00 10.00 S
ATOM 643 N ALA B 92 -1.541 -4.371 -5.366 1.00 10.00 N
awk -F">" '{if($2 != ""){fname=$2}if($2 == ""){term=$1;system("grep "term" F1/"fname" >>F1/"fname"_results");}}' data.txt
我认为单靠
sed
是无法做到这一点的。您需要一个循环来读取文件data.txt。例如,使用bash
脚本:
#!/bin/bash
# First remove all possible "problematic" characters from data.txt, storing result
# in data.clean.txt. This removes everything except A-Z, a-z, 0-9, leading >, and ..
sed 's/[^A-Za-z0-9>\.]//g;s/\(.\)>/\1/g;/^$/d' data.txt >| data.clean.txt
# Next determine which lines to keep:
cat data.clean.txt | while read line; do
if [[ "${line:0:1}" == ">" ]]; then
# If input starts with ">", set remainder to be the current file
file="${line:1}"
else
# If value is in sixth column, add "keep" to end of line
# Columns assumed separated by one or more spaces
# "+" is a GNU extension, so we need the -r switch
sed -i -r "/^[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ +$line +/s/$/keep/" $file
fi
done
# Finally delete the unwanted lines, i.e. those without "keep":
# (assumes each file appears only once in data.txt)
cat data.clean.txt | while read line; do
if [[ "${line:0:1}" == ">" ]]; then
sed -i -n "/keep/{s/keep//g;p;}" ${line:1}
fi
done
假设gnu awk,从包含
data.txt
的目录运行此命令:
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C
ATOM 615 H LEU B 208 3.361 -5.394 -6.021 1.00 10.00 H
ATOM 616 HA LEU B 211 2.930 -4.494 -3.302 1.00 10.00 H
ATOM 631 CG MET B 88 -0.828 -0.688 -7.575 1.00 10.00 C
ATOM 632 SD MET B 88 -2.380 -0.156 -6.830 1.00 10.00 S
ATOM 643 N ALA B 92 -1.541 -4.371 -5.366 1.00 10.00 N
awk -F">" '{if($2 != ""){fname=$2}if($2 == ""){term=$1;system("grep "term" F1/"fname" >>F1/"fname"_results");}}' data.txt
这将解析data.txt
中的文件名和搜索项,然后从awk
内部调用grep
,将data.txt
中列出的每个文件和项的匹配项附加到F1
中名为originalfilename.txt\u results
的新文件中
如果要完全替换原始文件,则可以运行以下命令:
grep "^>.*$" data.txt | sed 's/>//' | xargs -I{} find F1 -name {}_results -exec mv F1/{}_results F1/{} \;
这个解决方案使用了一些记录分隔符:“data.txt”使用>作为记录分隔符,而其他文件使用换行符
awk '
BEGIN {RS=">"}
FNR == 1 {
# since the first char in data.txt is the record separator,
# there is an empty record before the real data starts
next
}
{
n = split($0, a, "\n")
file = "F1/" a[1]
newfile = file ".new"
RS="\n"
while (getline < file) {
for (i=2; i<n; i++) {
if ($6 == a[i]) {
print > newfile
break
}
}
}
RS=">"
system(sprintf("mv \"%s\" \"%s.bak\" && mv \"%s\" \"%s\"", file, file, newfile, file))
}
' data.txt
awk'
开始{RS=“>”}
FNR==1{
#由于data.txt中的第一个字符是记录分隔符,
#在实际数据开始之前有一个空记录
下一个
}
{
n=拆分($0,a,“\n”)
file=“F1/”a[1]
newfile=文件“.new”
RS=“\n”
while(getline”
系统(sprintf(“mv\%s\”\%s.bak\”&&mv\%s\\%s\”,文件,文件,新文件,文件))
}
'data.txt
这将把F1中的所有文件移动到名为“备份”的tmp目录,然后在F1下重新创建生成的非空文件
mv F1 backup &&
mkdir F1 &&
awk '
NF==FNR {
if (sub(/>/,"")) {
file=$0
ARGV[ARGC++] = "backup/" file
}
else {
tgt[file,$0] = "F1/" file
}
next
}
(FILENAME,$6) in tgt {
print > tgt[FILENAME,$6]
}
' data.txt &&
rm -rf backup
如果您也想要空文件,这只是一个很小的调整,如果您想要保留备份目录,只需在最后去掉“&&rm..”
(无论如何,在测试期间都要这样做)
编辑:仅供参考,在这种情况下,您可以认为getline并非完全错误,因为它解析的第一个文件在结构和意图上与其他文件完全不同,因此解析一个不同于其他文件的文件不会在以后引起任何维护问题:
mv F1 backup &&
mkdir F1 &&
awk -v data="data.txt" '
BEGIN {
while ( (getline line < data) > 0 ) {
if (sub(/>/,"",line)) {
file=line
ARGV[ARGC++] = "backup/" file
}
else {
tgt[file,line] = "F1/" file
}
}
}
(FILENAME,$6) in tgt {
print > tgt[FILENAME,$6]
}
' &&
rm -rf backup
mv F1备份&&
mkdir F1&&
awk-v data=“data.txt”'
开始{
而((getline0){
如果(子(/>/,“”,第行)){
文件=行
ARGV[ARGC++]=“备份/”文件
}
否则{
tgt[文件,行]=“F1/”文件
}
}
}
(文件名,$6)在tgt中{
打印>tgt[文件名,$6]
}
' &&
rm-rf备份
但是正如您所看到的,它使脚本变得有点复杂(尽管效率稍高,因为现在主体中没有对FNR==NR的测试).谢谢你的回答。你的代码与我的示例很好地配合。但是对于大文件,我没有得到正确的输出。它只打印几行。如果你在我的示例中增加行数,你可以理解其中的区别。@user1606106:Hmm。我现在就来研究一下。有没有可能发送那些大文件给我?如果可以,请使用和一些我猜是压缩的原因。@user1606106:我已经为您更新了脚本。它现在应该可以很好地处理非常大的文件。如果您有任何问题,请告诉我。HTH。@steve getline是多余的,因为awk读取一个文件中的所有行而没有它,所以就像您有一个脚本/工具在读取行{workon line}时执行
并将其修改为道德等效的读取行{IF some condition{WHILE read otherline{workon otherline}}
。即使在安全的情况下,这也不是一个很好的方法…上面的getline方法与我发布的非getline解决方案之间的问题的简单示例。忽略初始文件。假设您希望增强脚本以额外打印每个选定文件第17行的第4个字段?使用getline方法,您需要引入一个变量,用于计算读取的行数,然后调用split(),而对于非getline,您只需使用FNR和$4。您可以删除“行”变量来免费获取拆分,但是您已经丢失了原始的$0。您可以创建一个变量来存储它…明白吗?这只是一个混乱的解决方法。谢谢您的回答。当我运行您的代码时,我收到错误“预期一元运算符”。如何解决此错误?在我的环境中,对我来说可以。但建议将[
更改为[[
可能会有帮助,将]
更改为]]
。这是否有效?更好的建议是:将两个${line:0:1}
替换为“${line:0:1}”
。您的data.txt
可能有一个空行或类似的内容。我添加了对data.txt的初始清理,以删除除a-Z、a-Z、0-9、leading>和之外的所有内容,以防一些无关字符破坏script.uooc,并且对于包含以空格开头或结尾的行或包含反斜杠或alrea的文件将失败请记住keep这个词。谢谢你的回答。当我运行你的代码时,我在表达式中遇到了错误^invalid char“”。如何解决这个错误?不知道。我在测试时没有遇到任何错误。你是否剪切、粘贴或重新键入了?如果文件名包含空格,并且不安全地使用getline,则会失败(不测试它的返回)。也不确定所有非呆滞AWK(只允许RS中的单个字符)是否会处理RS=“\n”