使用 awk 查找具有特定两行模式的文件

使用 awk 查找具有特定两行模式的文件

我有几百个具有这种模式的文件

@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
 1  3  5  ar
@<TRIPOS>SUBSTRUCTURE

其中,有些文件缺少后面的行,@<TRIPOS>BOND它们看起来像

@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE

我正在尝试查找工作目录中所有缺少数字行的文件,并将@<TRIPOS>BOND它们移动到另一个目录。我知道这是一项简单的任务,但我对 Linux 还很陌生。

注意:文件的长度和行号各不相同,这就是为什么我在字符串后“grepping”该行@<TRIPOS>BOND

这是我的一个代码,我原本打算把它写在 for 循环中。它没有起到作用,但我还是把它展示出来,以展示我的一次尝试。

cat file | grep -A1 '@<TRIPOS>BOND' | awk 'FNR == 2 {print}'

谢谢

答案1

如果你的 grep 版本支持 PCRE 模式(-P),你可以尝试多行匹配,查找后面@<TRIPOS>BOND跟着(仅在换行符之后)的实例@<TRIPOS>SUBSTRUCTURE,例如

grep -lzP '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' *

\Q在这种情况下,and可能\E没有必要,但旨在强制文字匹配(如果@, >,<在 Perl 正则表达式语法中具有特殊含义)。-l告诉 grep 列出匹配的文件而不是打印匹配。然后,您可以将文件列表用作命令的输入,mv例如

grep -lzP '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' * | xargs mv -t /path/to/newdir/


附加信息

你可以将比赛的第二部分表达为展望但我不认为在这种情况下它有任何优势

grep -lzP '\Q@<TRIPOS>BOND\E\n(?=\Q@<TRIPOS>SUBSTRUCTURE\E)' *

pcregrep(不是标准 Ubuntu 系统的一部分,但可从存储库获取)中的等效表达式将是这样的

pcregrep -lM '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' *

pcregrep -lM '\Q@<TRIPOS>BOND\E\n(?=\Q@<TRIPOS>SUBSTRUCTURE\E)' *

答案2

怎么样

for file in *.txt; do 
    grep -A1 "@<TRIPOS>BOND" "$file" | grep -q SUBSTR && mv "$file" bad_files/
done

解释:

这将循环遍历.txt当前目录中的所有文件(将 blob 更改为与您的文件匹配的任何内容)并将每个文件另存为$file。然后它将搜索$file@<TRIPOS>BOND打印该行和下一行。这将通过下一个grep静默(-q)查找SUBSTR,如果找到它,则意味着后面的行BONDSUBSTRUCTURE而不是您想要的数字行,因此它会将当前文件移动到文件夹bad_files

答案3

事情没那么简单:

find -type f -exec \
 awk '/@<TRIPOS>BOND/{getline; \
  if ($0 !~ /1  3  5  ar/){\
  printf "mv %s /path/to/move/%s\n", FILENAME, FILENAME}}' {} \; \
| bash

解释:

  • find -type f:查找当前工作目录中的所有文件
  • awk '/@<TRIPOS>BOND/{getline; \:查找文件内的行并移动到下一行
  • if ($0 !~ /1 3 5 ar/){\:如果下一行不是(!~)您想要的“数字行”
  • printf "mv %s /path/to/move/%s\n", FILENAME, FILENAME}}' {} \; \:构建一个 mv 命令并通过管道将其传输到......
  • | bash:...bash 并执行它。

因此该命令将把所有不包含数字行的文件复制到名为的目录中/path/to/move/

答案4

使用 awk 完成这个任务非常简单。下面是我的例子。我创建了两个文件file-nm(用于未丢失)和file-m(用于丢失),以及moved我们要移动的文件的目录。

awk '/@<TRIPOS>BOND/ {getline; if ($0 == "@<TRIPOS>SUBSTRUCTURE" ) system("mv \""FILENAME"\" moved")}' file-nm file-m

在这里,我们找到@<TRIPOS>BOND字符串,进入下一行,并检查该行是否为@<TRIPOS>SUBSTRUCTURE。如果是,我们用“mv”进行系统调用,找到的文件的文件名,并将“moved”作为目标。结果如下:

$ ls
file-m  file-nm  moved


$ awk '/@<TRIPOS>BOND/ {getline; if ($0 == "@<TRIPOS>SUBSTRUCTURE" ) system("mv \""FILENAME"\" moved")}' file-nm file-m      


$ ls                                                                                                                     
file-nm  moved


$ ls moved                                                                                                               
file-m

相关内容