Обработка текста в bash выполняется медленно. Строковые манипуляции с использованием чистого bash подходят для текста, который у вас уже есть в переменных, или для чтения очень маленьких файлов. Я подозреваю, что файлы вычислительной биологии обычно не будут маленькими, поэтому используйте такой инструмент, как awk
, который имеет небольшую стоимость запуска, но обрабатывает текст намного быстрее, чем bash.
Предполагая, что вы действительно хотите разделить свой pdb
файл:
awk -v RS='\nEND\n' '{ fn="frame" NR ".pdb"; print > fn; close(fn) }' "$filename"
Заставьте awk использовать \ nEND \ n
в качестве разделителя входных записей вместо новой строки, тогда вы можете даже использовать его счетчик записей. Разделитель выходной записи по-прежнему используется по умолчанию ORS = "\ n"
. (очень приятное предложение Костаса. Я настроил его так, чтобы END
должен был быть в начале строки, и добавил close
, чтобы убедиться, что он не использует тонну файла- дескрипторы на входах с очень большим количеством конформаций.)
Моя первоначальная идея заключалась в следующем:
awk 'BEGIN{i=0; fn="frame0.pdb"}
!/^END/ { print > fn; }
/^END/{ close(fn); fn="frame" ++i ".pdb"; }' \
"$filename"
awk кэширует дескрипторы файлов, поэтому несколько print> fn
не приводят к повторному открытию файла. ( close (fn)
делает это. Это делается просто для эффективности, поэтому awk не приводит к загрузке открытых файлов.)
Логика такова: вывести каждую полную строку в текущее имя файла. Когда вы увидите строку END
, перейдите к следующему имени файла. Если после последнего END
нет другой строки, то новое имя файла никогда не будет записано, и не будет создан рудиментарный последний файл.
OTOH, если вы хотите что-то сделать с массивом строковых блоков в памяти:
# add a `!/^END/` condition to the concat block if you want to avoid a stray newline after each END
awk 'BEGIN{i=0}
!/^END/ { arr[i] = arr[i] $0 "\n"; } # concat onto this array element
/^END/ { i++; }
END{for (k in arr) { print arr[k]; > ("frame" k ".pdb") } }' \
"$filename"
Тогда у вас есть awk-массив строк, который вы можете использовать в блоке END
. У него хорошие функции регулярных выражений.
Неудачная попытка bash, управляющего sed (nvm, завершается неудачно, потому что sed
не читает по одному байту, как оболочка читает
):
i=0
while true; do
outf="frame${i}.data";
##### DON'T USE THIS, sed READS TOO MUCH #####
strace -o sed.tr sed '/^END/q42' > "$outf"; # strace to see that the 2nd sed invocation finds the file empty
ret=$?;
((i++));
if [[ $ret == 0 ]];then # sed didn't see END before EOF
[[ -s $outf ]] || rm -f "$outf"; # clean up empty last file
break;
elif [[ $ret != 42 ]]; then
echo some other sed error;
break;
fi;
done < "$filename"
grep
раствор:
grep -q '.\.sql$' file.txt && grep -v '\.sql$' file.txt > output_file.txt
Второй grep
оператор/команда будет выполняться только в том случае, если первый вернул нулевой статус выхода 0
, если найдено какое-либо совпадение с шаблоном .\.sql$
Окончательный output_file.txt
контент:
actual.class
actual1.class
actual2.class
actual3.class
actual4.class