Изменение столбца нескольких файлов csv

У меня есть файл csv, называемый script1.csv, в котором во втором столбце есть имена столбцов, такие как «0-4 года с высоким риском», «65+ лет первый ответчик» и т. Д. Есть 20 таких значений. 21-я строка, 2-я колонка имеет ту же запись, что и в 1-й строке второго столбца. Я хотел бы переименовать эти значения в p1-p20, соответственно. Таким образом, 21-я строка будет иметь тег p1. Все без кавычек. У меня есть 150 таких файлов с именем script1.csv, script2.csv … Как это сделать? Ниже приведен пример для более короткого файла:

t, group, 1, 3, 5 0, 0-4 years low risk, 0, 0, 0 0, 0-4 years high risk, 0, 0, 1 ....., .... 0, 0-4 years low risk, 0, 0, 0 

Ожидаемый результат для каждого файла:

  t, group, 1, 3, 5 0, p1, 0, 0, 0 0, p2, 0, 0, 0 ....., .... 0, p1, 0, 0, 0 

Вот словарь, который мне нужен:

 0-4 years first responder p1 0-4 years high risk p2 ....... 65+ years low risk p19 65+ years pregnant women p20 

Поскольку у вас нет GNU AWK и не установлена sponge :

 <<<"$(<treatables-000.csv)" awk -F ',' -v OFS=',' 'NR!=1{$2="p"(NR-2)%20+1}1' >treatables-000.csv 
  • -F ',' : устанавливает разделитель полей ввода в,;
  • -v OFS=',' : устанавливает разделитель выходного поля в,;
  • NR!=1{$2="p"(NR-2)%20+1}1 : если текущий номер записи больше 1 , устанавливает второе поле в строку, состоящую из символа p за которым следует результат выражение (NR-2)%20+1 и печатает запись;
 % cat treatables-000.csv t,group,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205,207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,257,259,261,263,265,267,269,271,273,275,277,279,281,283,285,287,289,291,293,295,297,299,301,303,305,307,309,311,313,315,317,319,321,323,325,327,329,331,333,335,337,339,341,343,345,347,349,351,353,355,357,359,361,363,365,367,369,371,373,375,377,379,381,383,385,387,389,391,393,395,397,399,401,403,405,407,409,411,413,415,417,419,421,423,425,427,429,431,433,435,437,439,441,443,445,447,449,451,453,455,457,459,461,463,465,467,469,471,473,475,477,479,481,483,485,487,489,491,493,495,497,499,501,503,505,507 0,0-4 years low risk,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 0,0-4 years high risk,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 % <<<"$(<treatables-000.csv)" awk -F ',' -v OFS=',' 'NR!=1{$2="p"(NR-2)%20+1}1' >treatables-000.csv % cat treatables-000.csv t,group,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205,207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,257,259,261,263,265,267,269,271,273,275,277,279,281,283,285,287,289,291,293,295,297,299,301,303,305,307,309,311,313,315,317,319,321,323,325,327,329,331,333,335,337,339,341,343,345,347,349,351,353,355,357,359,361,363,365,367,369,371,373,375,377,379,381,383,385,387,389,391,393,395,397,399,401,403,405,407,409,411,413,415,417,419,421,423,425,427,429,431,433,435,437,439,441,443,445,447,449,451,453,455,457,459,461,463,465,467,469,471,473,475,477,479,481,483,485,487,489,491,493,495,497,499,501,503,505,507 0,p1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 0,p2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 

Чтобы повторить это для всех файлов, соответствующих поддеревам шаблонов treatables-???.csv в текущем рабочем каталоге, вы можете использовать цикл Bash for :

 for f in treatables-???.csv; do <<<"$(<"$f")" awk -F ',' -v OFS=',' 'NR!=1{$2="p"(NR-2)%20+1}1' >"$f"; done 

Вы можете выполнить задачу с помощью цикла, nl ( n umbering l ine) и sed ( s tring e ditor)

 for f in scenario*.csv do #next will numerate all lines exept first (started without number) nl -bp^[0-9] -nln -w1 "$f" | sed ' #add the «p» before line number s/^[0-9]/p&/ #put «pNUM» on the place of second field started with «NUM-NUM» s/\(^p[0-9]*\)\s*\([0-9]*,\s*\)[0-9]-[0-9][^,]*/\2\1/ #removes spaces from the line begining (may be for header only) s/^\s*// ' > out.tmp #outputs changed lines into temporary file mv out.tmp "$f" #move temp file to original done rm out.tmp #delete temp file 

Я понимаю, что у вас есть список уникальных фраз и вы хотите заменить первую фразу в списке «p1», вторая – «p2» и так далее. Это можно сделать следующим образом, если вы хотите сохранить ширину столбца:

 for filename in *.csv; do awk ' BEGIN { FS = "," n = 0 } { if (NR > 1) { if (!($2 in p)) { n++ p[$2] = n } $2 = "p" p[$2] } for (i = 1; i <= NF; i++) { sub("^[ ]+", "", $i) if (i != NF) { $i = $i "," } } # Add more columns and adjust the column widths to # your liking here. printf "%-3s%-10s%-3s%-3s%-3s\n", $1, $2, $3, $4, $5 } ' "$filename" > "$filename.tmp" mv "$filename.tmp" "$filename" done 

Вот скрипт perl, который выполняет эту работу.

Вы можете добавить больше шаблонов и замену хэшам %patterns мере необходимости. Не забывайте запятую в конце каждой строки.

Обратите внимание, что шаблоны интерпретируются как регулярные выражения, а не как литеральные строки. Поэтому, если ваши шаблоны имеют любые специальные символы регулярного выражения (например, * , ( , ) , ? , + т. Д.), Они должны быть экранированы с помощью \ (например, \* , \( , \) , \? \+ ).

Скрипт слегка меняет результат, поскольку он объединяет все поля с помощью ,\t (запятая и одна вкладка), где исходный вход имеет несколько пробелов. Если это важно, вы можете настроить этот оператор печати для получения того же или подобного вывода (например, используя printf а не print join() )

 $ cat bissi.pl #! /usr/bin/perl use strict; # optimisation: use qr// for the search patterns so that # the hash keys are pre-compiled regular expressions. # this makes the for loop later MUCH faster if there are # lots of patterns and lots of input lines to process. my %patterns = ( qr/0-4 years low risk/ => 'p1', qr/0-4 years high risk/ => 'p2', qr/65\+ years low risk/ => 'p19', qr/65\+ years pregnant women/ => 'p20', ); while(<>) { chomp; my @line = split /,\s*/; foreach my $key (keys %patterns) { # perl arrays are zero based, so $line[1] is 2nd field if ($line[1] =~ m/$key/) { $line[1] = $patterns{$key} ; last; } } print join(",\t",@line), "\n"; } 

Это дает следующий вывод:

 $ ./bissi.pl input.txt t, group, 1, 3, 5 0, p1, 0, 0, 1 0, p2, 0, 0, 0 0, p1, 0, 0, 0 

Чтобы преобразовать все 150 ваших файлов, вы обернете это в оболочку для цикла примерно так:

 mkdir -p new for i in {1..150} ; do ./bissi.pl "scenario$i.csv" > "new/scenario$i.csv" done