파일 이름의 처음 5자를 파일의 각 줄에 추가합니다.

파일 이름의 처음 5자를 파일의 각 줄에 추가합니다.

내 폴더에 ".txt" 파일이 많이 있습니다.

각 .txt 파일에 대해 파일 이름의 처음 5자를 가져와 파일의 각 줄 시작 부분에 추가해야 합니다. 또한 새 파일의 각 줄 시작 부분에 "*" 기호를 추가해야 합니다.

다음 명령을 사용해 보았지만 파일의 줄당 공백이 두 개 이상인 파일에서 잘못된 출력이 발생했습니다.

awk 'FNR == 1 {chr =substr(FILENAME, 0,5); name = FILENAME ".new" }{ printf("%s %s\n", "*"chr$1, $2) >name}' *.txt 

누군가 코드를 수정하거나 이를 수행하는 더 쉬운 방법을 제안할 수 있습니까?

답변1

쉘 루프를 사용하여 파일을 반복하겠습니다(쉘이 ${param:offset:length}ksh93의 연산자를 지원한다고 가정).

for f in *.txt
do
    sed -i -- "s/^/*${f:0:5} /" "$f"
done

(파일 이름에 백슬래시, 개행 문자 또는 &문자가 포함되어 있지 않다고 가정).

내가 선호하는 것은 데이터가 모두 완료되면 새 파일에 데이터를 쓴 다음 교체하는 것입니다.모두. 이렇게 하면 중단된 프로세스를 처리할 수 있습니다. 하지만 그건 내가 여기서 하는 일이 아닙니다.

답변2

데이터를 출력할 때 각 줄의 처음 두 필드만 처리할 이유가 없습니다. 그냥 인쇄하면 됩니다 $0(전체 원래 줄).

awk '
    FNR == 1 { close(name); chr = substr(FILENAME, 3, 5); name = FILENAME ".new" }
    { printf "*%s %s\n", chr, $0 >name }' ./*.txt

원하는 경우 print "*" chr, $0 >name이 명령문 대신 사용할 수 있습니다.printf

또는 쉘 루프를 사용하십시오.

for name in *.txt; do
    PREFIX=${name:0:5} awk '{ printf "*%s %s\n", ENVIRON["PREFIX"], $0 }' <"$name" >"$name.new"
done

여기서는 사용 중인 쉘이 , , , , busybox sh 와 같은 ksh93의 연산자를 지원한다고 가정합니다. ( 와도 함께 작동 ) 또는 POSIXly: 대신 와 함께 사용됩니다 .${param:offset:length}ksh93bashzshmkshyash${name[1,5]}${name:0:5}zsh${name%"${name#?????}"}

답변3

사용행복하다(이전 Perl_6)

~$ raku -e 'for @*ARGS {                                          \ 
                my $str  = .substr(0..4);                         \ 
                my @body = .IO.lines.map({ "*" ~ $str ~ $_ });    \
                spurt($_ ~ "_new", @body.join("\n") ~ "\n" );     \
            };'   *.txt

또는:

~$ raku -e 'for @*ARGS ->  $filename {                                   \
                my $str  = $filename.substr(0..4);                       \
                my @body = $filename.IO.lines.map({ "*" ~ $str ~ $_ });  \
                spurt($filename ~ "_new", @body.join("\n") ~ "\n" )      \
            };'   *.txt  

Raku는 Perl 계열의 프로그래밍 언어입니다. Raku에서는 @*ARGS쉘 명령줄에 인수를 저장하는 배열입니다. 간단히:

  • for배열을 사용하여 @*ARGS반복합니다 .
  • 각 인수(예: 파일 이름, here 또는 ) substr의 처음 5자를 사용하여 ,$_$filename$str
  • 각 인수(예: 파일 이름)는 IO객체 로 변환되어 lines전체를 읽습니다. 각 줄의 시작 부분에 합계가 추가되도록 줄이 수정되고, 수정된 줄은 다음 위치 *에 저장됩니다.$str@body
  • 출력은 spurt()파일 경로(즉, 새로 생성된 파일의 이름)와 @body적절한 개행 문자가 추가된 작성될 수정된 텍스트( )를 사용하는 메서드에 의해 생성됩니다.

샘플 입력(샘플 파일 이름 fileA):

>TCONS_00000867
>TCONS_00001442
>TCONS_00001447
>TCONS_00001528
>TCONS_00001529
>TCONS_00001668
>TCONS_00001921
>TCONS_00001922

출력 예( fileA_new, 필요에 따라 텍스트 수정):

*fileA>TCONS_00000867
*fileA>TCONS_00001442
*fileA>TCONS_00001447
*fileA>TCONS_00001528
*fileA>TCONS_00001529
*fileA>TCONS_00001668
*fileA>TCONS_00001921
*fileA>TCONS_00001922

https://course.raku.org/essentials/positionals/args-array/
https://docs.raku.org/언어/variables#@*ARGS
https://docs.raku.org/type/independent-routines#sub_spurt
https://raku.org

답변4

각 줄의 시작 부분에 다음을 추가합니다 "*<first-5-bytes> ".

perl -pi -e '$_ = "*" . substr($ARGV, 0, 5) . " $_"' -- *.txt

바이트 대신 처음 5자를 앞에 추가하려면 로케일의 문자 인코딩에 따라 파일 이름의 바이트에서 자체적으로 디코딩됩니다.

perl -MEncode::Locale -MEncode -pi -e '
  $_ = "*".
       encode(locale => substr(decode(locale_fs => $ARGV), 0, 5)).
       " $_"' -- *.txt

또는 각 줄에서 "decode+substr+encode"를 수행하지 마십시오.

perl -MEncode::Locale -MEncode -pi -e '
  $prefix = "*".
     encode(locale => substr(decode(locale_fs => $ARGV), 0, 5)).
     " $_" if $. == 1;
  $_ = $prefix . $_;
  close ARGV if eof' -- *.txt

áéíóú123.txt예를 들어 이는 UTF-8 로케일로 호출되는 파일에 영향을 미칩니다.

이러한 구별이 존재하는 일부 비 POSIX 시스템에서도 locale_fs대신 사용하면 작동할 수 있습니다.locale

관련 정보