내 폴더에 ".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}
ksh93
bash
zsh
mksh
yash
${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