更新(行の20%を取得):

更新(行の20%を取得):

たとえば、N個のファイル(file1、file2、file3...)があります。

そのうち最初の20%が必要で、結果ディレクトリは(file1_20、file2_20、file3_20 ...)と同じでなければなりません。

wcこれを使用してファイルの行数を取得し、0.2を掛けたいと思います。

その後、get 20%を使用してhead新しいファイルにリダイレクトしますが、自動化する方法がわかりません。

答え1

したがって、動作する例を作成します。

root@crunchbang-ibm3:~# echo {0..100} > file1        
root@crunchbang-ibm3:~# cat file1
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

次のコマンドを使用してファイルサイズをバイト単位で取得できますstat

root@crunchbang-ibm3:~# stat --printf %s "file1"
294

次に、次を使用してbcサイズに0.2を掛けることができます。

root@crunchbang-ibm3:~# echo "294*.2" | bc
58.8

しかし、浮動小数点を得たので、これを整数に変換してみましょうheadddこの方法も機能します)。

root@crunchbang-ibm3:~# printf %.0f "58.8" 
59

最後に、file1の最初の20%(バイトの提供またはインポート):

root@crunchbang-ibm3:~# head -c "59" "file1" 
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

それらを合わせると、次のことができます。

mkdir -p a_new_directory
for f in file*; do
    file_size=$(stat --printf %s "$f")
    percent_size_as_float=$(echo "$file_size*.2" | bc)
    float_to_int=$(printf %.0f "$percent_size_as_float")
    grab_twenty=$(head -c "$float_to_int" "$f")
    new_fn=$(printf "%s_20" "$f") # new name file1_20
    printf "$grab_twenty" > a_new_directory/$new_fn
done

fforループが実行されているディレクトリで見つかったエントリのプレースホルダはどこにありますか?file*

終了後:

root@crunchbang-ibm3:~# cat a_new_directory/file1_20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 

更新(行の20%を取得):

行の最初の20%を取得するには、次のようstat --printf %s "$f"に置き換えることができます。

wc -l < "$f"

を使用しているので、printf効果的にbcfrom を丸めることができますが、.5ファイルの長さが 1~2 行に過ぎないと欠けています。したがって、丸める必要があるだけでなく、基本的に少なくとも1つの行を取得する必要があります。

答え2

ダニ。私はアーカイブを解析する複雑な方法を使用して完全な答えを書いていますtar。これはとても素敵なことです。しかし、結局私はこれらのどれも必要ではないことに気づきました。必要なのはsed少しシェル数学です。

set ./file[1-5];i=1 n=;eval "${n:=
}       sed -n  \"$(grep -c '.\|' "$@"|
        sed 's|\(.*\):\(.*\)|\
        $i,$(((\2/5)+(i+=\2)-\2))w \1|
        ')\" <<!$n"'$(cat "$@")'"$n!$n"

どんなファイルでもgrep -c行数をワイルドカードで指定し(私はワイルドカードでfile[1-5])、数を指定してsedから、シェルの少しの助けを借りて独自のスクリプトを作成します。catこちらの記事から入力を提供してください。これは、ファイルを読み込もうとしている間にファイルのsed1つを開いて書き始めると、何が起こるのかわからないためですcat。そして、サイズに応じてパイプよりもバッファを処理する方が少し良いと思います。しかし、私はそれについてあまり明確ではありません。

これにより、単一ストリーム内のすべてのファイルを読み取り、wそれに応じて出力を作成できます。ファイル番号を適切に増やすにはいくつかの設定が必要なので、恐れる必要はありませんgrep。以下は、実行中の操作を示すevalいくつかの出力です。set -x

+ set ./file1 ./file2 ./file3 ./file4 ./file5
+ i=1 n=
+ + grep -c .\| ./file1 ./file2 ./file3 ./file4 ./file5
        sed s|\(.*\):\(.*\)|\
        $i,$(((\2/5)+(i+=\2)-\2))w \1|

+ eval 
       sed -n  "
        $i,$(((18400/5)+(i+=18400)-18400))w ./file1

        $i,$(((18411/5)+(i+=18411)-18411))w ./file2

        $i,$(((18415/5)+(i+=18415)-18415))w ./file3

        $i,$(((18418/5)+(i+=18418)-18418))w ./file4

        $i,$(((18421/5)+(i+=18421)-18421))w ./file5" <<!
$(cat "$@")
!

+ cat ./file1 ./file2 ./file3 ./file4 ./file5
+ sed -n 
        1,3681w ./file1

        18401,22083w ./file2

        36812,40495w ./file3

        55227,58910w ./file4

        73645,77329w ./file5

ご覧のとおり、行はストリーム内の各ファイルの場所に基づいてアドレス指定され、wそのファイル名を読み取ると作成されます。ただし、重要なのは、パス名から移植できない文字を処理しようとしないことです。特に、この場合、sed writeコマンドは改行でファイル名引数を区切るため、パス名に新しい行を使用することはできません。必要に応じて、ln必要に応じてこの状況を簡単に解決できます。

wsedまた、単一のスクリプト内でサポートできるriteファイル記述子の数に制限があることにも言及したいと思います。これ仕様によると:

[sed必須]w多くの実装の歴史的慣行と一致する少なくとも10の異なるファイルがサポートされています。追加ですが、規制に準拠したアプリケーションをサポートするように実装することをお勧めします。超えてはいけないこの制限。

したがって、上記のコマンドは最大10個の同時読み取り/書き込みファイルをサポートし、すべてのPOSIXシステムに移植可能でなければなりません。この種のコンテンツがより多くのコンテンツを必要とする可能性がある公開スクリプトまたはアプリケーションに統合されている場合は、次のように前処理されます/tmp

: & set '"" "" "" "" "" "" "" "" "" "" ';n='
' f=/tmp/$$$!'_$((i+=1))' MAXw=[num]
while eval "set '$1$1' $1;exec <<!$n\$(((i=0)+\$#))$n!$n 
      i=\$(sed \"$(IFS=\ ;printf "\nw $f%.0s" $1)\")"
      [ "$(($#==i?(_i=i-1):(MAXw=_i)))" -lt "$MAXw" ]
do :;done; rm "/tmp/$$$!"*; unset _i i f n

sed...これは現場でかなり移植可能な能力測定基準でなければなりません。 GNUは約1秒でsed4093個の同時に開かれたファイルで停止しますw。ただし、これはおそらく私のシステムの最大値であり、影響を受ける可能性がありますulimit。完了すると$i、試行するたびにdoubles値が確認されるため、2560と5120$_iに残ります。$iループが閉じるときは、上記のより安全な値をデフォルトで$MAXw使用してください。主にファイルを開くことができない場合、すべてのsが戻り値を正しく設定するかどうかわからないためです。ただし、読者はそれを使用して目的の操作を実行できます。$_isedw

の初期[num]値は$MAXw実際の数(必要なwファイルの最大数は何でも)でなければならず、リテラル数ではありません[num]

ここにある文書化についてもう一度申し上げますが、私の考えにはこの場合にはそれと似た方が良い考えです。sed読み込み中に書き込み記述子を保持する必要があるため、同じ入力/出力名で何ができるかは不明です。しかし、簡単に使える代替案がある場合は、取る価値のある機会ではないと思います。

私のテストファイルは次のように生成されます。

for n in 1 2 3 4 5
do : & seq -s "$(printf "%015s--$n--%015s\n\t")" "$!" >"file$n"
done

...廃棄されたプロセスPIDのカーネルからかなり連続した疑似乱数を取得します。ファイル内容は、分割の不一致を示すように意図的に設計されています。サンプルセットの前後姿は次のとおりです。

今後:

for f in file[1-5]; do
nl -ba "$f" | sed -n '$p;$=;1,3p
'; done

     1  1               --1--             
     2          2               --1--     
     3          3               --1--     
  3681          3681               --1--  
3681
     1  1               --2--             
     2          2               --2--     
     3          3               --2--     
  3683          3683               --2--  
3683
     1  1               --3--             
     2          2               --3--     
     3          3               --3--     
  3684          3684               --3--  
3684
     1  1               --4--             
     2          2               --4--     
     3          3               --4--     
  3684          3684               --4--  
3684
     1  1               --5--             
     2          2               --5--     
     3          3               --5--     
  3685          3685               --5--  
3685

型が少し奇妙に見える場合は、最初の出力行の前に区切り文字列が挿入されてseqいない可能性があります。-s重要なのは、sedすべてがseqnl番号に同意するようです。それでも…

後ろに:...

  sed -n 
  1,737w ./file1

  3682,4418w ./file2

  7365,8101w ./file3

  11049,11785w ./file4

  14733,15470w ./file5
  ...
     1  1               --1--           
     2          2               --1--   
     3          3               --1--   
   737          737               --1-- 
737
     1  1               --2--           
     2          2               --2--   
     3          3               --2--   
   737          737               --2-- 
737
     1  1               --3--           
     2          2               --3--   
     3          3               --3--   
   737          737               --3-- 
737
     1  1               --4--           
     2          2               --4--   
     3          3               --4--   
   737          737               --4-- 
737
     1  1               --5--           
     2          2               --5--   
     3          3               --5--   
   738          738               --5-- 
738

それが簡単で効率的なストリーミングです。

答え3

上記のツールを使用してください。 + find:またはを使用して、行またはバイト1
のパーセンテージを取得します。ここでは、またはによって提供され、最後にそれに出力を書き込みます。 head -n perc filehead -c perc file
perc(( count / 5 ))
countwc -l < filewc -c < file
file_20

注:/演算子は最も近い整数に丸められているため、file*行/バイトcount < 5(so perc = 0)を持つすべてのファイルは空のファイルを生成しますfile*_20

上位20%のインポート - 行:

mkdir some_dir_name
find . -maxdepth 1 -iname 'file*' -exec sh -c 'head -n $(( $(wc -l < "$0") / 5 )) "$0" > some_dir_name/"$0"_20' {} \;

最初の20%を取得 - バイト:

mkdir some_dir_name
find . -maxdepth 1 -iname 'file*' -exec sh -c 'head -c $(( $(wc -c < "$0") / 5 )) "$0" > some_dir_name/"$0"_20' {} \;


1テキストレイアウトに応じて、2つの方法は、たとえば10行のテキスト例でかなり異なる結果を生成することがあります

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua.


Abstract

Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
ut aliquip ex ea commodo consequat. 

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum...

合計行の最初の20%=最初の2行:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua.

合計バイトの最初の20%=最初の行(切り捨て):

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do

関連情報