指定:「特別な」最初の行(フィールド名など)を持つ1つの大きなテキストデータファイル(CSV形式など)。
Wanted: coreutils split -l
コマンド。ただし、元のファイルのヘッダー行が結果の各部分の先頭に表示されるという追加の要件があります。
split
とhead
を混ぜるとうまくいくと思いますか?
これはrobhruska'sスクリプトを少しクリーンアップしたものです:
tail -n +2 file.txt | split -l 4 - split_
for file in split_*
do
head -n 1 file.txt > tmp_file
cat "$file" >> tmp_file
mv -f tmp_file "$file"
done
wc
、cut
、ls
、およびecho
が不要な場所を削除しました。ファイル名の一部を変更して、もう少し意味のあるものにしました。読みやすくするために、複数の行に分けました。
おしゃれにしたい場合は、ハードコードされたファイルを使用する代わりに、mktemp
またはtempfile
を使用して一時ファイル名を作成できます。
編集
GNU split
を使用すると、これを行うことができます。
split_filter () { { head -n 1 file.txt; cat; } > "$FILE"; }; export -f split_filter; tail -n +2 file.txt | split --lines=4 --filter=split_filter - split_
読みやすくするために分割:
split_filter () { { head -n 1 file.txt; cat; } > "$FILE"; }
export -f split_filter
tail -n +2 file.txt | split --lines=4 --filter=split_filter - split_
いつ --filter
を指定すると、split
は各出力ファイルに対してコマンド(この場合はエクスポートする必要がある関数)を実行し、コマンドの環境内の変数FILE
をファイル名に設定します。
フィルタースクリプトまたは関数は、出力コンテンツまたはファイル名に必要な操作を行うことができます。後者の例は、変数ディレクトリの固定ファイル名に出力することです:> "$FILE/data.dat"
例えば。
GNU coreutils split> = 8.13(2011):で新しい--filter機能を使用できます。
tail -n +2 FILE.in |
split -l 50 - --filter='sh -c "{ head -n1 FILE.in; cat; } > $FILE"'
[mg] awkを使用できます。
awk 'NR==1{
header=$0;
count=1;
print header > "x_" count;
next
}
!( (NR-1) % 100){
count++;
print header > "x_" count;
}
{
print $0 > "x_" count
}' file
100は、各スライスの行数です。一時ファイルを必要とせず、1行に配置できます。
私はBash-fuに関しては初心者ですが、この2つのコマンドの極悪非道を作り上げることができました。もっとエレガントなソリューションがあるはずです。
$> tail -n +2 file.txt | split -l 4
$> for file in `ls xa*`; do echo "`head -1 file.txt`" > tmp; cat $file >> tmp; mv -f tmp $file; done
これは、入力ファイルがfile.txt
、prefix
にsplit
引数を使用しておらず、split
のデフォルトで始まる他のファイルがないディレクトリで作業しているxa*
出力フォーマット。また、「4」を希望の分割線サイズに置き換えます。
これにより、大きなcsvが999行の断片に分割され、ヘッダーが各行の上部に表示されます
cat bigFile.csv | parallel --header : --pipe -N999 'cat >file_{#}.csv'
Ole Tangeの回答に基づきます。 (オレの答え:パイプパートでは行カウントを使用できません)
これは、Denis Williamsonのスクリプトのより堅牢なバージョンです。スクリプトは多くの一時ファイルを作成しますが、実行が不完全だった場合、それらが横になっていると残念です。それでは、シグナルトラップを追加しましょう( http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html を参照してから、 http://tldp.org/ LDP/abs/html/debugging.html )そして一時ファイルを削除します;とにかくこれはベストプラクティスです。
trap 'rm split_* tmp_file ; exit 13' SIGINT SIGTERM SIGQUIT
tail -n +2 file.txt | split -l 4 - split_
for file in split_*
do
head -n 1 file.txt > tmp_file
cat $file >> tmp_file
mv -f tmp_file $file
done
'13'を必要な戻りコードに置き換えます。ああ、とにかくmktempを使用する必要があります(他の人が既に示唆しているように)、トラップラインのrmから 'tmp_file'を削除します。キャッチするシグナルについては、シグナルのマニュアルページを参照してください。
ワンライナーに関する@Arkadyのコメントに触発されました。
split
はファイル名を表示しませんが、_--additional-suffix
_オプションを使用すると、期待する内容を簡単に制御できますrm $part
_を介した中間ファイルの削除(同じサフィックスを持つファイルがないと想定)MYFILE=mycsv.csv && for part in $(split -n4 --additional-suffix=foo $MYFILE; ls *foo); do cat <(head -n1 $MYFILE) $part > $MYFILE.$part; rm $part; done
証拠:
_-rw-rw-r-- 1 ec2-user ec2-user 32040108 Jun 1 23:18 mycsv.csv.xaafoo
-rw-rw-r-- 1 ec2-user ec2-user 32040108 Jun 1 23:18 mycsv.csv.xabfoo
-rw-rw-r-- 1 ec2-user ec2-user 32040108 Jun 1 23:18 mycsv.csv.xacfoo
-rw-rw-r-- 1 ec2-user ec2-user 32040110 Jun 1 23:18 mycsv.csv.xadfoo
_
そしてもちろん_head -2 *foo
_はヘッダーが追加されたことを確認します。
スクリプトを他の人のサイトから直接コピーする規則についてはよくわかりませんが、 Geekology には、動作することを確認するコメントをいくつか付けて、あなたがやりたいことを行うための素晴らしいスクリプトがあります。必ずtail
-n
+2
下部のコメントに記載されています。
マルコのawkバージョンが好きで、これから単純化されたワンライナーを採用しました。そこでは、分割分数を必要なだけ簡単に指定できます。
awk 'NR==1{print $0 > FILENAME ".split1"; print $0 > FILENAME ".split2";} NR>1{if (NR % 10 > 5) print $0 >> FILENAME ".split1"; else print $0 >> FILENAME ".split2"}' file
ロブとデニスのバージョンがとても好きだったので、改善したいと思いました。
これが私のバージョンです。
in_file=$1
awk '{if (NR!=1) {print}}' $in_file | split -d -a 5 -l 100000 - $in_file"_" # Get all lines except the first, split into 100,000 line chunks
for file in $in_file"_"*
do
tmp_file=$(mktemp $in_file.XXXXXX) # Create a safer temp file
head -n 1 $in_file | cat - $file > $tmp_file # Get header from main file, cat that header with split file contents to temp file
mv -f $tmp_file $file # Overwrite non-header containing file with header-containing file
done
違い:
awk
はパフォーマンスが優れているため、tail
の代わりにawk
を使用します。head | cat
行を使用します以下は、csvヘッダーを保持するために使用できる4ライナーです(使用:head、split、find、grep、xargs、およびsed)
csvheader = `head -1 bigfile.csv` split -d -l10000 bigfile.csv smallfile _ find。| grep smallfile_ | xargs sed -i "1s/^/$ csvheader\n /" sed -i '1d' smallfile_00
説明:
GNU Parallel:
parallel -a bigfile.csv --header : --pipepart 'cat > {#}'
各部分でコマンドを実行する必要がある場合は、GNU Parallelもこれを行うことができます。
parallel -a bigfile.csv --header : --pipepart my_program_reading_from_stdin
parallel -a bigfile.csv --header : --pipepart --fifo my_program_reading_from_fifo {}
parallel -a bigfile.csv --header : --pipepart --cat my_program_reading_from_a_file {}
CPUコアごとに2つの部分に分割する場合(例:24コア= 48等サイズの部分):
parallel --block -2 -a bigfile.csv --header : --pipepart my_program_reading_from_stdin
10 MBブロックに分割する場合:
parallel --block 10M -a bigfile.csv --header : --pipepart my_program_reading_from_stdin