私はこのスクリプトを私の関連する質問に受け取りました--- ファイル名とヘッダーをcsvの先頭に挿入するにはどうすればよいですか
find . -name '*.csv' -printf "%f\n" |
sed 's/.csv$//' |
xargs -I{} sed -i '1s/^/customer|/ '$'\n'' 1!s/^/{}|/' {}.csv;
現在、大きなファイルの場合はかなり時間がかかります。 50,000ファイルにスケーリングして、この結果を得ました。
real 1m41.251s
user 0m59.326s
sys 0m38.681s
100,000ファイルの場合、これを取得しました。
real 3m18.466s
user 1m58.451s
sys 1m16.550s
du -sh
100,000ファイルの場合は485Mになります。このデータを10〜20GBまでスケールアップしたいと思います。
上記のスクリプトを高速化する方法があるかどうか知りたいのですが。私は物事をスピードアップするためにどんなツールを使ってもかまいません。
それが助けになるなら、私はUbuntu 18.04.02 LTS、16GBRAMを使用しています。
time awk -i inplace -v OFS='|' 'FNR==1{cust=FILENAME; sub(/\.csv$/,"",cust)} {print (FNR>1 ? cust : "customer"), $0}' *.csv
real 0m20.253s
user 0m3.336s
sys 0m14.854s
最初のsed
:oよりも非常に高速です。理由はわかりませんが。誰かがそれを説明することができれば、それは本当に役に立ちます。
上記のスクリプトを100万ファイルにスケーリングすると、Argument list too long
と表示されます。
以下を試しましたが、遅いですが、
find . -name \*.csv -exec awk -i inplace -v OFS='|' 'FNR==1{cust=FILENAME; sub(/\.csv$/,"",cust)} {print (FNR>1 ? cust : "customer"), $0}' {} \;
バッチでやっても、10万ファイルは遅いようです。
time find . -name "10*.csv" -exec awk -i inplace -v OFS='|' 'FNR==1{cust=FILENAME; sub(/\.csv$/,"",cust)} {print (FNR>1 ? cust : "customer"), $0}' {} \;
real 9m29.474s
user 2m3.336s
sys 6m37.822s
Edの回答を使用して通常のforループを試しましたが、元のファイルが生成されたのと同じ速度で、100万レコードで約40分動作するようです。
for file in *.csv; do
echo "$file"
awk -i inplace -v OFS='|' 'FNR==1{cust=FILENAME; sub(/\.csv$/,"",cust)} {print (FNR>1 ? cust : "customer"), $0}' "$file"
done
100,000ファイルごとにls
とxargs
を使用してバッチ処理を試みましたが、Edが最初に提供したソリューションとして、これは妥当なようです。
time ls 11*.csv | xargs awk -i inplace -v OFS='|' 'FNR==1{cust=FILENAME; sub(/\.csv$/,"",cust)} {print (FNR>1 ? cust : "customer"), $0}'
real 0m23.619s
user 0m3.537s
sys 0m15.272s
time ls 12*.csv | xargs awk -i inplace -v OFS='|' 'FNR==1{cust=FILENAME; sub(/\.csv$/,"",cust)} {print (FNR>1 ? cust : "customer"), $0}'
real 0m25.044s
user 0m3.892s
sys 0m16.261s
time ls 13*.csv | xargs awk -i inplace -v OFS='|' 'FNR==1{cust=FILENAME; sub(/\.csv$/,"",cust)} {print (FNR>1 ? cust : "customer"), $0}'
real 0m24.997s
user 0m4.035s
sys 0m16.757s
私が今計画しているのは、上記のソリューションを使用し、forループを使用してバッチ処理することです。各バッチの平均が25秒であるとすると、25 * 10-> 4分で終了します。何百万ものレコードにとっては速いと私は感じています。
誰かがより良い解決策を持っているなら、私に知らせてください。上記のコードのいずれかが間違っている/悪い場合は、私に知らせてください。私はまだ初心者で、物事を不適切にコピーまたは理解した可能性があります。
$ awk -v OFS=',' 'FNR==1{cust=FILENAME; sub(/\.csv$/,"",cust)} {print (FNR>1 ? cust : "customer"), $0}' 10000000.csv
customer,first_name,middle_name,last_name,gender,email,phone_number,address,city,state,country,date_order_start,date_order_complete,invoice_number,invoice_date,item,item_price,quantity,cost,job_name,job_price,total_cost
10000000,Chae,Jesusa,Cummings,Female,[email protected],555-555-8750,911 Hauser Pike,Moline,Georgia,Cameroon,2016-06-29,2016-07-16,36298,2016-07-17,Acer,493.86,14,354.77,Broken,123.68,898.13
だからあなたができるどんなawkでも:
for file in *.csv; do
awk 'script' "$file" > tmp && mv tmp "$file"
done
またはGNU「インプレース」編集のawk:
$ tail -n +1 10000000.csv 10000001.csv
==> 10000000.csv <==
first_name,middle_name,last_name,gender,email,phone_number,address,city,state,country,date_order_start,date_order_complete,invoice_number,invoice_date,item,item_price,quantity,cost,job_name,job_price,total_cost
Chae,Jesusa,Cummings,Female,[email protected],555-555-8750,911 Hauser Pike,Moline,Georgia,Cameroon,2016-06-29,2016-07-16,36298,2016-07-17,Acer,493.86,14,354.77,Broken,123.68,898.13
==> 10000001.csv <==
first_name,middle_name,last_name,gender,email,phone_number,address,city,state,country,date_order_start,date_order_complete,invoice_number,invoice_date,item,item_price,quantity,cost,job_name,job_price,total_cost
Fleta,Rosette,Hurley,Other,[email protected],1-555-555-1210,35 Freelon Arcade,Beaverton,Rhode Island,Cayman Islands,2009-06-08,2009-06-29,39684,2009-07-01,NVIDIA GeForce GTX 980,474.31,16,395.79,Broken,157.53,1088.04
Bennett,Dennis,George,Male,[email protected],(555) 555-4131,505 Robert C Levy Arcade,Wellington,Louisiana,Mexico,2019-05-09,2019-05-19,37938,2019-05-21,8GB,187.67,16,205.77,Service,170.21,1007.85
Tommye,Pamula,Diaz,Other,[email protected],555.555.4445,1001 Canby Boulevard,Edinburg,Massachusetts,Gambia,2004-05-02,2004-05-24,31364,2004-05-26,Lenovo,137.21,13,193.63,Replacement,246.43,934.31
Albert,Jerrold,Cohen,Other,[email protected],+1-(555)-555-8491,1181 Baden Avenue,Menomonee Falls,Texas,Tajikistan,2019-08-03,2019-08-12,37768,2019-08-15,Intel® Iris™ Graphics 6100,396.46,17,223.02,Service,118.53,960.27
Louetta,Collene,Best,Fluid,[email protected],1-555-555-7050,923 Barry Viaduct,Laurel,Illinois,St. Barthélemy,2009-03-02,2009-03-06,39557,2009-03-07,AMD Radeon R9 M395X,133.9,11,198.49,Fix,178.54,1055.32
Kandace,Wesley,Diaz,Female,[email protected],+1-(555)-555-5414,341 Garlington Run,Santa Maria,New Jersey,Mexico,2005-10-09,2005-10-10,30543,2005-10-14,Samsung,590.29,5,354.85,Service,292.56,1032.22
。
$ awk -i inplace -v OFS=',' 'FNR==1{cust=FILENAME; sub(/\.csv$/,"",cust)} {print (FNR>1 ? cust : "customer"), $0}' 10000000.csv 10000001.csv
。
$ tail -n +1 10000000.csv 10000001.csv
==> 10000000.csv <==
customer,first_name,middle_name,last_name,gender,email,phone_number,address,city,state,country,date_order_start,date_order_complete,invoice_number,invoice_date,item,item_price,quantity,cost,job_name,job_price,total_cost
10000000,Chae,Jesusa,Cummings,Female,[email protected],555-555-8750,911 Hauser Pike,Moline,Georgia,Cameroon,2016-06-29,2016-07-16,36298,2016-07-17,Acer,493.86,14,354.77,Broken,123.68,898.13
==> 10000001.csv <==
customer,first_name,middle_name,last_name,gender,email,phone_number,address,city,state,country,date_order_start,date_order_complete,invoice_number,invoice_date,item,item_price,quantity,cost,job_name,job_price,total_cost
10000001,Fleta,Rosette,Hurley,Other,[email protected],1-555-555-1210,35 Freelon Arcade,Beaverton,Rhode Island,Cayman Islands,2009-06-08,2009-06-29,39684,2009-07-01,NVIDIA GeForce GTX 980,474.31,16,395.79,Broken,157.53,1088.04
10000001,Bennett,Dennis,George,Male,[email protected],(555) 555-4131,505 Robert C Levy Arcade,Wellington,Louisiana,Mexico,2019-05-09,2019-05-19,37938,2019-05-21,8GB,187.67,16,205.77,Service,170.21,1007.85
10000001,Tommye,Pamula,Diaz,Other,[email protected],555.555.4445,1001 Canby Boulevard,Edinburg,Massachusetts,Gambia,2004-05-02,2004-05-24,31364,2004-05-26,Lenovo,137.21,13,193.63,Replacement,246.43,934.31
10000001,Albert,Jerrold,Cohen,Other,[email protected],+1-(555)-555-8491,1181 Baden Avenue,Menomonee Falls,Texas,Tajikistan,2019-08-03,2019-08-12,37768,2019-08-15,Intel® Iris™ Graphics 6100,396.46,17,223.02,Service,118.53,960.27
10000001,Louetta,Collene,Best,Fluid,[email protected],1-555-555-7050,923 Barry Viaduct,Laurel,Illinois,St. Barthélemy,2009-03-02,2009-03-06,39557,2009-03-07,AMD Radeon R9 M395X,133.9,11,198.49,Fix,178.54,1055.32
10000001,Kandace,Wesley,Diaz,Female,[email protected],+1-(555)-555-5414,341 Garlington Run,Santa Maria,New Jersey,Mexico,2005-10-09,2005-10-10,30543,2005-10-14,Samsung,590.29,5,354.85,Service,292.56,1032.22
コマンドラインで渡すにはファイルが多すぎて、xargsを介して実行するのが遅すぎる場合は、別のオプションがあります。
awk -i inplace ... '
BEGIN {
while ( (getline line < ARGV[1]) > 0 ) {
if ( line ~ /\.csv$/ ) {
ARGV[ARGC] = line
ARGC++
}
}
ARGV[1] = ""
}
{ the "real" script }
' <(ls)
上記は、ls
の出力を引数としてではなく入力ファイルとして読み取り、引数の配列に.csv
で終わるファイル名を入力し、ファイルをあたかもそうであったかのように操作します。コマンドラインで引数として渡されます。
次の2つのアプローチを試すことができます。
$ find . -name \*.csv -type f ! -empty -exec \
Perl -spe 's/^/,/;
$F //= $ARGV =~ s/\.csv$//r;
s/^/$. == 1 ? "\n$C" : $F/e;
undef $F, close ARGV if eof;
' -- -C="Customer" {} +
2つ目は、Gnu sed機能、特にFコマンドを使用してファイル名を取得し、-sオプションを使用して複数のファイルを単一のストリームとしてではなく個別に処理します。
$ find . -name \*.csv -type f ! -empty -exec \
sed -se 'F;1s/^/CUSTOMER,/' {} + |
sed -E \
-e 'N;s/.*\.csv(\nCUSTOMER,)/\1/;t' \
-e 's/\.csv\n/,/;s/..//' \
;