列をコマンドの結果に置き換える

列をコマンドの結果に置き換える

ファイル内の各行の列値をコマンドの出力にすばやく効率的に置き換える方法を見つけようとしています。 1日に50万行程度の複数のファイルを処理する必要がありますが、できるだけ早く作業を終了できることを探しています。

コンマで区切られた行の8番目の列を入力に取り、コマンドを実行し、その列をコマンドの出力に置き換える必要があります。

私が試した方法は次のとおりです。動作しますが、非常に遅いです。

awk -F "," 'NR > 1 {
    cmd = "cdrtoip " $8
    cmd | getline ip
    close(cmd)
    $8=ip
    print
}' $1.csv >> $1.csv.tmp

私はBashやLinuxサーバーにプリインストールできる他のLinuxプログラムを使用することを好みます。

編集:申し訳ありません。 cdrtoipが何であるかを含める必要がありました。

# Convert CISCO format (signed integer) to Hex
# Capitalize or else conversion from hex to decimal doesn't work later
HEXIP=$(printf '%x\n' $1 | tr '[:lower:]' '[:upper:]')

# Negative numbers will get 8 'f' in front of them
# Trim that part off
if [[ ${#HEXIP} -eq 16 ]]; then
    HEXIP=${HEXIP:8:8}
fi

# Convert hex to decimal, separate into octets, put in order
OCTETS[0]=$(echo "ibase=16; ${HEXIP:6:2}" | bc)
OCTETS[1]=$(echo "ibase=16; ${HEXIP:4:2}" | bc)
OCTETS[2]=$(echo "ibase=16; ${HEXIP:2:2}" | bc)
OCTETS[3]=$(echo "ibase=16; ${HEXIP:0:2}" | bc)

# Print the IP
echo ${OCTETS[0]}.${OCTETS[1]}.${OCTETS[2]}.${OCTETS[3]}

cdripの実行時間は次のとおりです。

    0.23s real     0.00s user     0.02s system

ベストアンサー1

ネイティブアプリを使い続けたいと言っているのはわかりますが、GNUパラレル別々のプロセスを並列に実行できるため、より高速に実行できます。

sudo apt-get update
sudo apt-get install parallel
awk -F',' '{print $8}' file.csv | parallel -j+0 cdrtoip {}

これを呼び出す方法はいくつかありますが、parallel上記の方法は.csvファイルの列8から出力を取得し、cdrtoipシステムの各行でコアごとに1つのプロセスを同時に実行します。したがって、デフォルトで4つのコアを実行すると、通常の実行時間の25%以内にタスクを実行できます。

利点parallelは、出力を追跡し、実行中のタスクであるかのように順番に生成することです。

インストールしたら、man parallel実行方法の詳細を確認してください(またはリンクのマニュアルを確認してください)。これがあなたが探しているものではない場合は申し訳ありません。しかし、過去には何度も役に立ちました。

編集する:出力を.csvに追加して列8を置き換えるには、次の例を使用します。〜する働いて、持つテスト済みです。デュアルコアMacbook Proで5,000行の.csvファイルを実行するのに約3.25分かかります。

設定:

$ cat file.tmp
blah1,blah2,blah3,blah4,blah5,blah6,blah7,1175063050,blah9,blah10,blah11

$ for i in {1..5000}; do cat file.tmp; done > file.csv

$ wc -l < file.csv
5000

スクリプト(cdrtoip提供されたスクリプトを使用):

$ cat csvjob.sh
#!/bin/bash

fragment1="$(cut -d, -f1-7 file.csv | tr ',' "\t")"
fragment2="$(cut -d, -f8 file.csv | parallel -j+0 cdrtoip {})"
fragment3="$(cut -d',' -f9- file.csv | tr ',' "\t")"

paste <(echo "$fragment1") <(echo "$fragment2") <(echo "$fragment3") | sed "s/\t/,/g" > newfile.csv

結果:

$ time ./csvjob.sh
real    3m23.092s
user    1m22.245s
sys     2m57.794s

$ head -3 newfile.csv
blah1,blah2,blah3,blah4,blah5,blah6,blah7,10.10.10.70,blah9,blah10,blah11
blah1,blah2,blah3,blah4,blah5,blah6,blah7,10.10.10.70,blah9,blah10,blah11
blah1,blah2,blah3,blah4,blah5,blah6,blah7,10.10.10.70,blah9,blah10,blah11

別の編集: 以下はクアッドコアのMac Miniで実行されました(他のものも実行)。

$ time ./csvjob.sh
real    2m12.171s
user    2m59.816s
sys     2m15.787s

また、5,000行ではなく500,000行と言われたことに気づきました。その価値が何であるかについては、cdrtoip5,000回の連続実行に関する以下の統計を参照してください。

$ time for i in {1..5000}; do cdrtoip 1175063050; done > /dev/null
real    2m32.487s
user    1m26.537s
sys     1m8.270s

最終編集: 以下は、前述のように、すでに複数のアプリケーションを実行しているクアッドコアMac Miniで実行されている500,000行のファイルです。

$ time ./csvjob.sh

real    216m22.780s
user    301m40.694s
sys     239m44.404s

何を言うのか正確に知っている、OP。

並行して実行しても実行にはかなり長い時間がかかります。

OPはより良い解決策を見つけました。ファイルあたり126秒は他の追随を許しません。繰り返しますが、cdrtoip元々提供された500,000行の.csvを8コアDebian VM(OPがインストールできないことを知っています)で実行した統計は次のとおりです。parallel

$ time ./csvjob.sh
real    14m7.467s
user    6m3.883s
sys     4m18.556s

おすすめ記事