ファイル名の最初の5文字を​​ファイルの各行に追加します。

ファイル名の最初の5文字を​​ファイルの各行に追加します。

私のフォルダには「.txt」ファイルがたくさんあります。

各 .t​​xt ファイルのファイル名の最初の 5 文字を取得し、ファイルの各行の先頭に追加する必要があります。また、新しいファイルの各行の先頭に「*」記号を追加する必要があります。

次のコマンドを試してみましたが、1行に1つの空白が複数あるファイルで誤った出力が発生しました。

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

データを出力するときに各行の最初の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

関連情報