たとえば、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
しかし、浮動小数点を得たので、これを整数に変換してみましょうhead
(dd
この方法も機能します)。
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
f
forループが実行されているディレクトリで見つかったエントリのプレースホルダはどこにありますか?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
効果的にbc
from を丸めることができますが、.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
こちらの記事から入力を提供してください。これは、ファイルを読み込もうとしている間にファイルのsed
1つを開いて書き始めると、何が起こるのかわからないためです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
w
riteコマンドは改行でファイル名引数を区切るため、パス名に新しい行を使用することはできません。必要に応じて、ln
必要に応じてこの状況を簡単に解決できます。
w
sed
また、単一のスクリプト内でサポートできる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秒でsed
4093個の同時に開かれたファイルで停止しますw
。ただし、これはおそらく私のシステムの最大値であり、影響を受ける可能性がありますulimit
。完了すると$i
、試行するたびにdoubles値が確認されるため、2560と5120$_i
に残ります。$i
ループが閉じるときは、上記のより安全な値をデフォルトで$MAXw
使用してください。主にファイルを開くことができない場合、すべてのsが戻り値を正しく設定するかどうかわからないためです。ただし、読者はそれを使用して目的の操作を実行できます。$_i
sed
w
の初期[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
すべてがseq
行nl
番号に同意するようです。それでも…
後ろに:...
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 file
head -c perc file
perc
(( count / 5 ))
count
wc -l < file
wc -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