如何在bash中将文件传回一个循环?

时间:2013-10-28 15:43:54

标签: bash loops for-loop

我正试图想办法从文件中删除一对行,该对中的第一行包含唯一的id,第二行包含一个字符串。

我正在思考一些事情
for i in $(cat idlist.txt ); do grep -v -A1 $i file1 

但是我不确定如何在每次迭代时将循环输出反馈到它中?有什么提示吗?

我正在改变的文件基本上是

的格式
uniqueID.1
OJNEFONEOIWENWEJNEWEJ
uniqueID.2
HHTHANJAHTNTHAJNTEOEJ

我想要一些ID +字符串。

由于

2 个答案:

答案 0 :(得分:0)

在这种情况下,

awk可能是一个很好的工具选择。这是基本概念的快速版本,包含在bash脚本中:

#!/bin/bash

awk '
FNR == 1 { filenum++ }
filenum == 1 { ids[$0] = 1 }
filenum == 2 {
    if ((FNR % 2) == 1) { id = $0 }
    else if (ids[id] != 1) { print id; print }
}
' idlist.txt file.txt

想法是通过向关联数组ids添加要忽略的标记来处理idlist文件,然后以成对的行处理第二个文件,注意第一行的id,然后打印它和如果ID不在ids中,则为下一行。

如果您需要“就地”修改文件,那么已经建议的mv内容可以在此处使用。

文稿:

$ cat idlist.txt 
id.2
id.4
id.6
$ cat file.txt 
id.1
stuff 1
id.2
stuff 2
id.3
stuff 3
id.4
stuff 4
id.5
stuff 5
id.6
stuff 6
id.7
stuff 7
$ ./skipper.sh 
id.1
stuff 1
id.3
stuff 3
id.5
stuff 5
id.7
stuff 7

答案 1 :(得分:0)

为列表中的每个模式读取和写入文件似乎效率很低。最好一次读取和处理文件,一次性删除所有ID。

如何执行此操作取决于您在该文件idlist.txt中获得的ID类型。从您将模式传递给grep的方式来看,它们看起来好像必须是单词或简单的正则表达式,因此您可以尝试以下方法。

首先,将ID转换为sed程序:

PROGRAM=$(while read ID; do echo "/$ID/{N;d;}"; done < idlist.txt)

然后使用sed运行程序并就地更新文件:

sed -i '' -e "$PROGRAM" -- file1

程序的工作方式是/$ID/匹配包含id的行,然后N命令读取文件中的下一行,d命令删除这两行。其他线条通常打印。 (显然这取决于$ID是一个不包含/个字符的有效基本正则表达式。)

如果您的sed版本接受“扩展正则表达式”(程序的GNU版本的-r选项,或BSD版本的-E选项) ,然后你可以将所有的ID编译成一个正则表达式:

PROGRAM=$(printf '/('; tr '\n' '|' < idlist.txt; printf '.^)/{N;d;}')
sed -r -i '' -e "$PROGRAM" -- file1

(这里.^是一个不可能匹配的正则表达式;它遵循正则表达式中的最后|,以确保交替中的最后一个子句没有匹配。)