У меня есть несколько сотен файлов с таким шаблоном
@<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.
Примечание: файлы различаются по длине и номерам строк, поэтому я «подбираю» строку после строки @<TRIPOS>BOND
.
Вот один из моих кодов, которые я планировал написать в цикле for. Это не делает работу, но я показываю это, чтобы показать одно из моих испытаний.
cat file | grep -A1 '@<TRIPOS>BOND' | awk 'FNR == 2 {print}'
Спасибо
Если Ваша версия grep поддерживает режим PCRE (-P
) Вы могли попробовать многострочное соответствие, которое находит экземпляры @<TRIPOS>BOND
это сопровождается (только после новой строки) @<TRIPOS>SUBSTRUCTURE
например.
grep -lzP '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' *
\Q
и \E
может быть ненужным в этом случае, но предназначаются для принуждения литерала, соответствующего (в случае, если @
, >
, <
имейте особое значение в Perl regex синтаксис). -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)' *
Как насчет
for file in *.txt; do
grep -A1 "@<TRIPOS>BOND" "$file" | grep -q SUBSTR && mv "$file" bad_files/
done
Это циклично выполнится через все .txt
файлы в текущем каталоге (изменяют на блоб к любым соответствиям Ваши файлы) и сохраняют каждого как $file
. Это будет затем искать $file
для @<TRIPOS>BOND
и печать это и следующая строка. Это передается через следующее grep
который тихо (-q
) ищет SUBSTR
, если это находит его, это означает что строка после BOND
SUBSTRUCTURE
а не числовая строка Вы хотите так, она переместит текущий файл в папку bad_files
.
Дело не в этом простой:
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
:... колотите и выполните его.Таким образом, команда будет mv весь файл, которые не являются contianing числовая строка к названному каталогу /path/to/move/
.
nawk '/^@<TRIPOS>BOND/{getline;if( $0 ~ /^@/){print "mv", FILENAME, "../NewLoc/"}}' * | bash
Задачей является довольно простое использование 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 "ИМЯ ФАЙЛА файла, который был найден, и" переместился" как место назначения. Вот результат:
$ 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
awk
или gawk
awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" <bad_files>/$(basename \""FILENAME"\")")} exit}' <file_name>
Объяснение
/@<TRIPOS>BOND/,/@/
Нам нужен только блок между @<TRIPOS>BOND
и следующая строка, запускающаяся с @
getline
Считайте следующую строку после @<TRIPOS>BOND
if ($_ ~ /^@/)
Проверьте, если строка запускается с a @
true
Распечатайте сообщение
printf "%s:%s\n",$_,FILENAME
Переместите файл
system ("mv \""FILENAME"\" <bad_files>/$(basename \""FILENAME"\")")
false
Оставьте сценарий
exit
Пример
$ cat foo
@<TRIPOS>ATOM
2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE
$ cat bar
@<TRIPOS>ATOM
2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
1 3 5 ar
@<TRIPOS>SUBSTRUCTURE
$ awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" \""FILENAME"\"_moved")} exit}' foo
@<TRIPOS>SUBSTRUCTURE:foo
$ awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" \""FILENAME"\"_moved")} exit}' bar
$ cat foo_moved
@<TRIPOS>ATOM
2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE
$ cat bar_moved
cat: bar_moved: No such file or directory