열 추가, 파일 이름(".csv" 제외)으로 전체 열 채우기 - BaSH의 여러 파일에 대해

열 추가, 파일 이름(".csv" 제외)으로 전체 열 채우기 - BaSH의 여러 파일에 대해

주의 사항: 완전 초보자입니다. 열 헤더가 "이름"일 수 있는 .csv 파일에 열을 추가해야 하지만 전체 열은 파일 자체의 이름, filename. 이제 각 파일에는 변수가 3개만 있지만 행은 2,100개입니다.

예: 파일의 경우"bcc1_45Fall_10010002.csv"이게 내가 갖고 있는 거야 -

   HUC8       YEAR    RO_MM
   10010002   1961    74.7
   10010002   1962    69.1
   10010002   1963    52.0
   10010002   1964   130.7
   10010002   1965    32.2
   10010002   1966    85.4

이것이 내가 원하는거야 -

  NAME                   HUC8       YEAR    RO_MM
  bcc1_45Fall_10010002   10010002   1961    74.7
  bcc1_45Fall_10010002   10010002   1962    69.1
  bcc1_45Fall_10010002   10010002   1963    52.0
  bcc1_45Fall_10010002   10010002   1964   130.7
  bcc1_45Fall_10010002   10010002   1965    32.2
  bcc1_45Fall_10010002   10010002   1966    85.4

아니면 이거 -

  HUC8                    YEAR    RO_MM
  bcc1_45Fall_10010002    1961    74.7
  bcc1_45Fall_10010002    1962    69.1
  bcc1_45Fall_10010002    1963    52.0
  bcc1_45Fall_10010002    1964   130.7
  bcc1_45Fall_10010002    1965    32.2
  bcc1_45Fall_10010002    1966    85.4

"HUC8" 열의 모든 데이터를 간단히 대체할 수 있다면 filename완벽할 것입니다. 추가 열일 필요는 없습니다.

수천 개의 파일에 대해 이 작업을 수행해야 합니다.

첫 번째 부분을 수행하는 방법을 알고 있다면 루프를 만들 수 있습니다. 하지만 더 좋은 방법이 있을까요?

어디서부터 시작해야할지 모르겠습니다.

답변1

awk및 사용 column:

$ awk '
  NR==1{ sub(/\.csv$/, "", FILENAME) } # remove .csv suffix from FILENAME
  NR>1{ $1=FILENAME }                  # replace the first field with filename
  1                                    # print record
' bcc1_45Fall_10010002.csv | column -t
HUC8                  YEAR  RO_MM
bcc1_45Fall_10010002  1961  74.7
bcc1_45Fall_10010002  1962  69.1
bcc1_45Fall_10010002  1963  52.0
bcc1_45Fall_10010002  1964  130.7
bcc1_45Fall_10010002  1965  32.2
bcc1_45Fall_10010002  1966  85.4

수정된 파일을 디렉토리에 저장하려면 쉘 루프에서 이를 실행할 수 있습니다 modified_files.

mkdir modified_files &&
for i in *.csv; do
  awk 'NR==1{ sub(/\.csv$/, "", FILENAME) } NR>1{ $1=FILENAME }1' "$i" |
    column -t > "./modified_files/$i"
done

열을 교체해야 하는데 HUC8이것이 첫 번째 열이 아닌 경우 코드를 다음과 같이 변경합니다.

awk -v search='HUC8' '
  NR==1{
    for(i=1;i<=NF;i++)
      if ($i==search){ fld=i; sub(/\.csv$/, "", FILENAME); break }
  }
  NR>1{ $fld=FILENAME }
  1
' file.csv | column -t

답변2

사용밀러, 파일이 "단순" CSV(쉼표 없음)라고 가정합니다.이내에필드 등 - 전체 RFC-4180 지원이 필요한 경우 --csvlite변경할 수 있습니다)--csv

$ cat bcc1_45Fall_10010002.csv
HUC8,YEAR,RO_MM
10010002,1961,74.7
10010002,1962,69.1
10010002,1963,52.0
10010002,1964,130.7
10010002,1965,32.2
10010002,1966,85.4

그 다음에

  1. 현재 HUC8열을 바꾸려면 다음을 수행하십시오.

     $ mlr --csvlite put -S '$HUC8 = substr(FILENAME,0,-5)' bcc1_45Fall_10010002.csv
     HUC8,YEAR,RO_MM
     bcc1_45Fall_10010002,1961,74.7
     bcc1_45Fall_10010002,1962,69.1
     bcc1_45Fall_10010002,1963,52.0
     bcc1_45Fall_10010002,1964,130.7
     bcc1_45Fall_10010002,1965,32.2
     bcc1_45Fall_10010002,1966,85.4
    
  2. 별도의 열을 추가하려면 다음을 수행하세요 Name.

     $ mlr --csvlite put -S '$Name = substr(FILENAME,0,-5)' bcc1_45Fall_10010002.csv
     HUC8,YEAR,RO_MM,Name
     10010002,1961,74.7,bcc1_45Fall_10010002
     10010002,1962,69.1,bcc1_45Fall_10010002
     10010002,1963,52.0,bcc1_45Fall_10010002
     10010002,1964,130.7,bcc1_45Fall_10010002
     10010002,1965,32.2,bcc1_45Fall_10010002
     10010002,1966,85.4,bcc1_45Fall_10010002
    
  3. Name열을 첫 번째 열로 추가하려면 다음을 수행하십시오 .

     $ mlr --csvlite put -S '$Name = substr(FILENAME,0,-5)' then reorder -f Name bcc1_45Fall_10010002.csv
     Name,HUC8,YEAR,RO_MM
     bcc1_45Fall_10010002,10010002,1961,74.7
     bcc1_45Fall_10010002,10010002,1962,69.1
     bcc1_45Fall_10010002,10010002,1963,52.0
     bcc1_45Fall_10010002,10010002,1964,130.7
     bcc1_45Fall_10010002,10010002,1965,32.2
     bcc1_45Fall_10010002,10010002,1966,85.4
    

위의 모든 내용은 결과를 표준 출력에 기록합니다. 파일을 내부에서 수정하려면 옵션을 추가하세요 -I. 쉘 글로브 ex를 사용하여 한 번에 여러 파일을 전달할 수 있습니다. bcc*.csv또는 *.csv.

[테스트할 때없이 -I레코드 이질성으로 인해 새 헤더가 필요하지 않는 한 헤더 행은 반복되지 않습니다. 그러나 -I적절한 헤더가 각 파일에 추가됩니다.]

답변3

$ perl -lne 'BEGIN {$fnr=1};

             if ($fnr == 1) {
               ($fn = $ARGV) =~ s/\.[^.]+$//;
               print "NAME,$_"
             } else {
               print "$fn,$_"
             };

             $fnr++;

             if (eof) {$fnr=1}' *.csv

그러면 파일 이름(.csv "확장자" 제외)이 첫 번째 필드로 추가되고 .csv 파일의 내용이 stdout에 인쇄됩니다.

awk와 달리 는 perl각 개별 파일의 줄 수를 추적하지 않습니다(변수를 사용하여 총 줄 수만 추적함 $.). 이 스크립트는 먼저 $fnrBEGIN 블록에 변수를 설정한 다음 읽은 각 줄에 대해 변수를 증가시키고 마지막으로 파일 끝에 도달할 때마다 다시 1로 재설정하여 해당 개수를 수동으로 유지합니다 .

파일 이름을 첫 번째 필드가 아닌 마지막 필드로 추가하도록 쉽게 수정됩니다. 예를 들어 두 print명령문을 다음과 같이 변경합니다.

      print "$_,NAME"
and: 
      print "$_,$fn"

첫 번째 필드가 아닌 줄의 다른 곳에 파일 이름 필드를 삽입해야 하는 경우 Perl의 splice기능을 사용할 수 있습니다.

예를 들어, 다음은 파일 이름을 세 번째 필드로 삽입합니다(perl 배열 인덱스는 1이 아닌 0부터 시작하므로 세 번째 필드는 가 $F[2]아니라 입니다 $F[3]).

$ perl -F, -lne 'BEGIN {$fnr=1; $field_num=2};

             if ($fnr == 1) {
               ($fn = $ARGV) =~ s/\.[^.]+$//;
               splice @F, $field_num, 0, "NAME";
             } else {
               splice @F, $field_num, 0, $fn;
             };

             print join(",", @F);

             $fnr++;

             if (eof) {$fnr=1}' *.csv

이는 Perl의 -F옵션을 사용하여 쉼표를 필드 구분 기호로 설정합니다. 이는 또한 Perl의 자동 분할 기능을 사용하여 입력 행을 배열로 자동 분할할 수 있도록 합니다 @F(이는 입력 행을 $1, $2, $3 등으로 자동 분할하는 awk의 기본 동작과 유사합니다). 리터럴 문자열 "NAME" 또는 수정된 파일 이름이 @F로 이어진 다음 배열의 요소가 @F쉼표 문자로 결합되어 인쇄됩니다.

마지막으로 파일의 내용을 실제로 변경하려면 Perl의 -i옵션을 사용하십시오. 선택적으로 옵션과 함께 "확장자"를 사용하여 원본 파일의 백업을 유지할 수 있습니다 -i(예: filename.csv로 이름 바꾸기 filename.csv.orig) -iorig. 예를 들어:

perl -iorig -lne '......' *.csv

또는

perl -iorig -F, -lne '......' *.csv

답변4

그런 다음 awk를 사용하여 파일 이름을 반복하고 열을 인쇄합니다.

for f in *.csv;
do
    head -1 $f > out/$f
    cat $f | awk -v FIN=${f%.csv} 'NR>1 {print FIN, $2, $3}' >> out/$f
done

HUC8       YEAR    RO_MM
bcc1_45Fall_10010002 1961 74.7 
(...)

관련 정보