読者です 読者をやめる 読者になる 読者になる

【bash】ls、grepの「引数が長すぎます」をawkで回避

黒魔術っぽくて敬遠していたawkをちょっと触ってみると、やっぱり黒魔術だった

github.com

# 基本1 標準出力を空白文字区切りで分割し、後のスクリプトっぽい部分で一つ目なら$1、二つ目なら$2と書く。
ls foo | awk '{print $1 $2}'

# 基本2 改行の分だけ動作を繰り返す
# ls -1 ... ファイルの一覧を改行区切りで標準出力
ls -1 foo | awk '{print $1}'

# 基本3 スクリプトっぽい部分"{ ... }"は bashではない。
# 独自(C言語っぽい?)文法。
ls -1 foo | awk '{
   print "----- " $1 " -----";
   # コマンドの字句を作成し、変数に保存
   command = sprintf("cat foo/%s", $1);
   
   # bash実行。
   buf = system(command);
   # ファイルディスクプリタを閉じる
   close(command);
   print "";
}'

# 基本4 演算できる。なんだこの気持ち悪いインタプリタ
echo 1 | awk '{ print $1 + 1 * 2 }'

# 基本5 if もループもできる。
echo 1 | awk '{
  for (i=1; i<100; i++)
  {
    sum += i;
    if (sum >= 100) {
      break;
    }
  }
  print "i:" i " sum:" sum;
}'

スクリプト置くならえんやこら手続きがいるけど、手順書に乗っけるだけならば検証作業はいりませんなぁ(ゲス顔) その代わり、結構遅いんやねこれ。。

本題

grep "" dir/*/*/*/*で、400byteのファイル×10万個ぐらいひっかけると、「引数が長すぎます」といわれて死んだ。 awkを使って、動的にコマンドを生成しつつ回避。

github.com

#/bin/bash

# ファイルが 数万個のところでlsとかすると、「引数が長すぎます」とエラーが出る。
# awkを使って疑似回避。
# 非常に重たい。
ls -1d msgs/*/* | awk '{
  command = sprintf("grep ERROR %s/*/*", $1);
  system(command);
  close(command);
}'