比較性能テスト受け入れられた回答

比較性能テスト受け入れられた回答

以下のようにabdというテキストファイルがあります。

48878 128.206.6.136
34782 128.206.6.137
12817 23.234.22.106

テキストからIPアドレスを抽出して保存したいです。変えるそして他の目的のために。

試してみました。

for line in `cat abd`
do

ip=`grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' $line`

echo $ip

done

以下のようにエラーが発生します。

grep: 34782: No such file or directory

grep: 128.206.6.137: No such file or directory

grep: 12817: No such file or directory

grep: 23.234.22.106: No such file or directory

ここで何が間違っているのかわかりません。どんな助けでも大変感謝します。

答え1

最初はほぼ当たった。答えは特定のケースに適用されますが、エラーが発生するのは、変数ではなくファイルを検索するためにawk使用しようとするためです。grep

また、正規表現を使用するときは常にgrep -E安全に使用してください。また、バックティックは使用されなくなりました$()

grepサポートされているシェルで変数を使用する正しい方法ここにある文字列次の3つは入力リダイレクトを使用しているため、<コマンドgrep$ip変数)は実際には次のようになります。

ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"

whileファイルを検索する場合は1行ずつ移動することが保証されるため、常にループを使用しますが、for奇妙な間隔がある場合は通常ループが発生します。また、cat入力リダイレクトに代わる役に立たない使用も実装しました。この試み:

while read line; do
  ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"
  echo "$ip"
done < "abd"

また、使用しているOSやバージョンが何であるかはわかりませんが、grep過去にこのコマンドを使用するたびに中括弧の前のエスケープ文字は通常必要ありません。引用符なしでバックティックなしで使用または使用することによって発生する可能性がありますgrep -E。わかりません。それを使用または使用せずに試してみて、何が起こっているのかを確認できます。

forループを使用するのかwhileループを使用するのかは、特定の状況にどのループが適しているのか、そして実行時間が最も重要であるかによって異なります。 OPは、各IPアドレスに別々の変数を割り当てようとするのではなく、ループ自体で使用できるように、行内の各IPアドレスに変数を割り当てたいと思います。この場合、$ip繰り返しごとに1つの変数が必要です。私はこの問題についてしっかりとした立場に立っています。

答え2

IPアドレスが常にファイルの2番目のフィールドである場合、またはawkcut使用して抽出できます。

awk '{print $2}' abd

または

cut -d' ' -f2 abd

IPアドレスを繰り返す必要がある場合は、通常forまたはループを使用できます。whileたとえば、

for ip in $(cut -d' ' -f2 abd) ; do ... ; done

または

awk '{print $2}' abd | while read ip ; do ... ; done

あるいは、すべてのIPアドレスを配列として読み取ることもできます。

$ IPAddresses=($(awk '{print $2}' abd))
$ echo "${IPAddresses[@]}"
128.206.6.136 128.206.6.137 23.234.22.106

答え3

grepファイルまたは標準入力からパターンを検索します。grepコマンドラインで一致させるデータ文字列を渡すことはできません。この試み:

grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' abd

変数の各IPアドレスを取得する必要がある場合:

grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' abd |
while read IP
do
    echo "$IP"
done

比較性能テスト受け入れられた回答

答えは、grep入力ファイルの各行で別々の呼び出しを実行することを示唆しています。 1000〜5000行のファイルで何が起こるのか見てみましょう。このファイルは、質問の元のサンプルファイルをコピーして作成されましたabd.1000abd.5000元のコードは、${1:?}ハードコードされた "abd"の代わりにファイル名をコマンドライン引数()として使用するように変更されました。

$ wc -l abd.1000 abd.5000
  1000 abd.1000
  5000 abd.5000
  6000 total

1000行のファイルでこの回答のサンプルコードをテストしてください。

$ cat ip-example.sh
#!/bin/sh
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' "${1:?}" |
while read IP
do
    echo "$IP"
done

$ time sh ip-example.sh abd.1000 > /dev/null

real    0m0.021s
user    0m0.007s
sys     0m0.017s
$

上記のこの回答の例は、1/4秒以内に1000行のファイルを処理します。それでは、許可された回答の例がどのように実行されるかを見てみましょう。

$ cat accepted.sh
#!/bin/bash
while read line; do
  ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"
  echo "$ip"
done < "${1:?}"

$ time bash accepted.sh abd.1000 > /dev/null

real    0m3.565s
user    0m0.739s
sys     0m2.936s
$

まあ。許可された回答の例は約3 1/2秒で実行されます。169倍遅いこの回答例では、1/40秒以上です。

もう少し頑張って5000行でテストしてみましょう。

$ time sh ip-example.sh abd.5000 > /dev/null

real    0m0.052s
user    0m0.051s
sys     0m0.029s

~について二重ただ処理する5倍のデータ

$ time bash accepted.sh abd.5000 > /dev/null

real    0m17.561s
user    0m3.817s
sys     0m14.333s

許容される回答のサンプルコードにはほとんど5倍長くなる1000行のデータより5倍多くのデータを処理しました。

結論として

許容される回答の例は次のとおりです。337倍長くなるこの回答のコードの代わりに5000行のファイルを処理してくださいip-example.sh(このページの他の回答も同様のことをする必要がありますip-example.h)。

答え4

最初の質問を見るバッシュFAQ:

while read -r _ ip; do printf "%s\n" "${ip[@]}"; done < abd
128.206.6.136
128.206.6.137
23.234.22.106

関連情報