zsh
подойдет больше, чем bash
для такого рода задач:
#! /bin/zsh -
files1=(1/*.out(n)) files2=(2/*.go.out(n))
for f1 f2 (${files1:^files2}) NOCI.py $f1 $f2 3/$f1:t:r+$f2:t
(n)
сортирует шарики численно, поэтому они обрабатываются в числовом порядке (, где Run_10
находится между Run_9
и Run_11
, а не между Run_1
и Run_2
без него ). ${array1:^array2}
:заархивирует два массива $file:t
:хвостовая часть файла (базовое имя)$filr:r
:корневая часть (удалить расширение ). В итоге мы бежим:
NOCI.py 1/Run_1.out 2/Sym_1.g0.out 3/Run_1+Sym_1.g0.out
NOCI.py 1/Run_2.out 2/Sym_2.g0.out 3/Run_2+Sym_2.g0.out
...
Общее решение с использованием GNU awk
было бы:
gawk 'NR>1{ for (i=2; i<=NF; i++) {
c[i][$1]= c[i][$1]?c[i][$1] s $i:$i;
} next;
}1;
ENDFILE{
for (x in c[2]) {
printf ("%s", x);
for (i=2;i<=NF;i++) { printf ("\t%s", c[i][x]); delete c[i][x]; };
print "";
};
}' s=', ' infile |column -s $'\t' -t
Приведенная выше команда загрузит не весь, а почти весь ваш входной файл в память, и вы сказали, что у вас 30 ГБ ОЗУ и размер вашего файла ~15 ГБ, поэтому, если у вас достаточно свободной памяти не менее 15 ГБ, будет не проблема, я думаю.
Но ниже приведен обходной путь, но не оптимальное решение для разделения вашего bigfile.txt на небольшие файлы, каждый из которых имеет одно и то же GeneName, а затем применить указанную выше команду awk
для всех этих файлов *.small
и сохранить вывод в один файл в режиме добавления..
Я говорю, что это не оптимально, потому что, возможно, распределение Генных Имен было неравным, и, возможно, некоторые из них меньше, а некоторые больше; впрочем, вот, пожалуйста:
Разделить входной файл на части небольшого размера в первом столбцеGene
:
awk 'NR>1{ print >$1".small"; }' bigfile.txt
Затем выполните приведенную выше команду awk
для *.small
файлов; Просто удалите условие NR>1
в начале, так как когда мы разделяем bigfile.txt, мы уже пропускаем его.
gawk '{... }; ENDFILE{... }' s=', ' *.small >>proccedfile
и удалить файлы rm *.small
позже.
Следующее предназначено для работы с огромными файлами, так как sort
требуется только для обработки всего файла одновременно, а sort
предназначено для решения этой проблемы с помощью пейджинга по запросу -и т. д., поэтому оно не на самом деле не нужно хранить весь ввод в памяти. В команде awk за один раз сохраняются только значения для текущего $1
, поэтому у него не будет проблем с памятью :
$ cat tst.sh
#!/usr/bin/env bash
awk -v OFS='\t' '{print (NR>1), NR, $0}' "${@:--}" |
sort -k1,1n -k3,3 -k2,2n |
cut -f 3- |
awk '
BEGIN { OFS="\t" }
NR == 1 { $1=$1; print; next }
$1 != prev { prt() }
{
for (i=2; i<=NF; i++) {
col[i] = (i in col ? col[i] ", " : "") $i
}
}
END { prt() }
function prt( i) {
if ( prev != "" ) {
printf "%s%s", prev, OFS
for (i=2; i<=NF; i++) {
printf "%s%s", col[i], (i<NF ? OFS : ORS)
}
}
delete col
prev = $1
}
'
$./tst.sh file
Gene col1 col2 col3
ACE 1, 2 0.4, 0.5 BP, DP
NOS2 1, 1.4, -0.1 1, 2.5, 0.2 BP, SP, DP
RPP-I.1 1 0.01 BP
Вывод вышеприведенного скрипта разделен на вкладки -, что, я полагаю, хорошо для вас, поскольку вы можете легко запускать на нем другие инструменты, импортировать его в электронную таблицу и т. д. Если вы хотите, чтобы он создавал визуально выровненные столбцы вместо этого добавьте | column -s $'\t' -t
в конец скрипта, НО тогда вы представили другую программу, которая потенциально должна считывать весь выходной файл в память, чтобы вычислить максимальную ширину поля перед печатью, поэтому YMMV. Если вы не можете жить с выводом, разделенным вкладкой -, и не можете использовать column
для создания табличного вывода, задайте новый вопрос именно об этом.
Вышеупомянутое также написано для работы независимо от того, поступает ли ввод из файла или конвейера.