используя команду вставки в цикле - PullRequest
3 голосов
/ 24 января 2012

Я использую Fedora и bash, чтобы сделать некоторые манипуляции с файлами, которые у меня есть. Я пытаюсь объединить большое количество файлов, каждый с двумя столбцами данных. Из этих файлов я хочу извлечь данные из второго столбца файлов и поместить их в один файл. Ранее я использовал следующий скрипт:

paste 0_0.dat 0_6.dat 0_12.dat | awk '{print $1, $2, $4}' >0.dat

Но это очень сложно, так как количество файлов увеличивается - пытаясь сделать это со 100 файлами. Поэтому я просмотрел сеть, чтобы увидеть, есть ли способ достичь этого простым способом, но подойти с пустыми руками.

Я бы хотел вызвать цикл for, если это возможно, например,

for i in $(seq 0 6 600)
do
  paste 0_0.dat | awk '{print $2}'>>0.dat
done

но это, конечно, не работает с командой вставки.

Пожалуйста, дайте мне знать, если у вас есть какие-либо рекомендации о том, как делать то, что я пытаюсь сделать ...

ФАЙЛ ДАННЫХ # 1 выглядит как показано ниже (ограничено пробелом)

-180 0.00025432
-179 0.000309643
-178 0.000189226
.
.
.
-1 2E-5
0 1.4E-6
1 0.00000
.
.
.
178 0.0023454268
179 0.002352534
180 0.001504992

ФАЙЛ ДАННЫХ № 2

-180 0.0002352
-179 0.000423452
-178 0.00019304
.
.
.
-1 2E-5
0 1.4E-6
1 0.00000
.
.
.
178 0.0023454268
179 0.002352534
180 0.001504992

Первый столбец идет от -180 до 180 с шагом 1.

DESIRED (n - количество столбцов и количество файлов)

-180 0.00025432 0.00025123 0.000235123 0.00023452 0.00023415 ... n
-179 0.000223432 0.0420504 0.2143450 0.002345123 0.00125235 ... n
.
.
.
-1 2E-5
0 1.4E-6
1 0.00000    
.
.
.
179 0.002352534 ... n
180 0.001504992 ... n

Спасибо

Ответы [ 4 ]

2 голосов
/ 24 января 2012

join может дать вам желаемый результат.

join <(sort -r file1) <(sort -r file2)

Тест:

[jaypal:~/Temp] cat file1
-180 0.00025432
-179 0.000309643
-178 0.000189226
[jaypal:~/Temp] cat file2
-180 0.0005524243
-179 0.0002424433
-178 0.0001833333
[jaypal:~/Temp] join <(sort -r file1) <(sort -r file2)
-180 0.00025432 0.0005524243
-179 0.000309643 0.0002424433
-178 0.000189226 0.0001833333

Чтобы сделать несколько файлов одновременно, вы можете использовать его с командой find -

find . -type f -name "file*" -exec join '{}' +
1 голос
/ 24 января 2012

Как насчет этого:

paste "$@" | awk '{ printf("%s", $1); 
for (i = 2; i < NF; i += 2) 
       printf(" %s", $i); printf "\n"; 
}'

Предполагается, что вы не столкнетесь с лимитом с paste (проверьте, сколько открытых файлов может быть).Обозначение "$@" означает «все приведенные аргументы, в точности как указано».Сценарий awk просто печатает $1 из каждой строки вставленного вывода, за которым следуют четные столбцы;с последующим переводом строки.Это не подтверждает, что нечетные столбцы все совпадают;возможно, было бы разумно сделать это, и вы могли бы написать смутно похожий цикл, чтобы сделать это в awk.Также не проверяется, совпадает ли количество полей в этой строке с числом в предыдущей строке;это еще одна разумная проверка.Но это делает всю работу за один проход по всем файлам - для фактически произвольного списка файлов.


У меня есть 100 входных файлов - как я могу использовать этот код для открытияэти файлы?

Вы поместили мой оригинальный ответ в скрипт 'filter-data';Вы вызываете скрипт с 101 именем файла, сгенерированным seq.Команда paste вставляет все 101 файл вместе;команда awk выбирает интересующие вас столбцы.

filter-data $(seq --format="0_%g.dat" 0 6 600)

Команда seq в формате выдаст 101 имя файла;Это 101 файл, который будет вставлен.

Вы могли бы даже обойтись без сценария filter-data:

paste $(seq --format="0_%g.dat" 0 6 600) | awk '{ printf("%s", $1); 
for (i = 2; i < NF; i += 2) 
printf(" %s", $i); printf "\n"; 
}'

Я бы, вероятно, выбрал более общий сценарий в качестве основного сценария.и, в случае необходимости, я бы создал «однострочник», который вызывает основной сценарий с конкретным набором аргументов, представляющих интерес в настоящее время.

Другой ключевой момент, который может быть камнем преткновения: pasteне ограничивается только 2 файлами;он может вставить столько файлов, сколько вы можете открыть (дать или взять около 3).

1 голос
/ 24 января 2012

Исходя из моих предположений, которые вы видите в комментариях выше, вам не нужно вставлять.Попробуйте это

awk '{
  arr[$1] = arr[$1] "\t" $2 }; 
  END {for (x=-180;x<=180;x++) print  x "\t" arr[x]
 }' *.txt \
| sort -n

Обратите внимание, что мы просто берем все значения в массив на основе значения в первом поле и добавляем значения на основе ключа $ 1.После того, как все данные были прочитаны, в разделе КОНЕЦ распечатывается ключ и значение.Я добавил такие вещи, как "x=", ":vals= ", чтобы помочь «объяснить», что происходит.Удалите их для полностью чистых данных, разделенных табуляцией.Измените '\ t' на ':' или '|', или ... вздрогните ',' если вам нужно.Измените *.txt на то, что указано в каждой вашей спецификации файла.

Имейте в виду, что все командные строки Unix имеют ограничения по количеству и размеру (длина имен файлов, а не данных внутри), имен файлов, которые могут быть обработаны за 1 вызов.Сообщите нам, если вы получите сообщение об ошибке.

Канал для сортировки гарантирует, что данные сортируются по столбцу 1.

С моими тестовыми данными, вывод был

-178            0.0001892261    0.0001892262    0.0001892263    0.000189226
-179            0.0003096431    0.0003096432    0.0003096433    0.000309643
-180            0.000254321     0.000254322     0.000254323     0.00025432
178             0.0001892261    0.0001892262    0.0001892263    0.000189226
179             0.0003096431    0.0003096432    0.0003096433    0.000309643
180             0.000254321     0.000254322     0.000254323     0.00025432

Основано на 4 входных файлах.

Надеюсь, это поможет.

PS Добро пожаловать в StackOverflow (SO) Не забудьте прочитать часто задаваемые вопросы, http://tinyurl.com/2vycnvr, проголосуйте за хорошееQ / A, используя серые треугольники, http://i.imgur.com/kygEP.png, и примите ответ, который решит вашу проблему, если таковой имеется, нажав знак галочки, http://i.imgur.com/uqJeW.png

0 голосов
/ 24 января 2012

Это может работать для вас:

echo *.dat | sed 's/\S*/<(cut -f2 &)/2g;s/^/paste /' | bash >all.dat
...