diff の結果を色付する

vim に結果を渡すと、diff の表示が色分け表示になって読みやすくなります。

diff -u old.txt new.txt | vim -R –

 diff -u は好きな書式指定で大丈夫です。
 
他にも、[[ColorDiff http://colordiff.sourceforge.net/]](FreeBSD ports: textproc/colordiff)というものもあります。
 
参考:
– [[diffの結果をvimで色付けして表示するグローバルエイリアスhttp://d.hatena.ne.jp/ysano2005/20061102/1162445347]]
  zsh のグローバルエイリアス版と、その他の方法が紹介されています。

コマンド引数の文字数制限 – Argument list too long

UNIX系OSで実行するコマンドの最大の長さは execve(2) の制限に依存するそうです。

プログラムの実行引数の制限については、長さの制限は OS によって異なり、FreeBSD では 64KB、Linux のあるディストリビューションでは 128KB、SunOS4〜Solaris は 1MB、HP-UX 10.20 までは 20KB (パッチを当てれば 2MB)、HP-UX 11.x 以降は 2MB です。

この値は伝統的に ARG_MAX というマクロ定数で定義されているため、使っている UNIX, Linux, Mac OS X の ARG_MAX を調べたい場合は /usr/include を ARG_MAX で grep するか、getconf コマンドを使って

% getconf ARG_MAX

結果:

65536

とすることで調べることができます。

FreeBSD なら sysctl で

% sysctl -A kern.argmax

結果:

kern.argmax: 65536

としてもいいです。
なお、ARG_MAX は 4096 以上であるべき、と POSIX には規定されています。

2017年2月現在のコマンドライン最大文字数の参考値が知りたくて、
手元のマシンいくつかで試してみました。

  • CentOS release 6.8 (Final / さくらのVPS) … 2621440文字

  • Scientific Linux release 6.2 (Carbon / さくらのVPS) … 2621440文字

  • Mac OS X Sierra (Macbook Pro 2015) … 262144文字

  • Debian(Jessie / さくらのクラウド) … 2097152文字

最低でも20万文字ということで、あまり気にする機会はなさそうですが、
もし大量のファイルを扱う場合などにArgument list too longエラーがでたときは、
以下のように xargs などを使うとARG_MAXの制限を回避できます。

grep foo /path/to/too-many-files/*

たとえばこのように、ワイルドカードでエラーが出てしまう場合、

echo /path/to/too-many-files/* | xargs grep foo

のように echo と xargs を組み合わせるとエラーなく動作します。

なぜこれならエラーにならないかというと、echoはプログラムではなくシェルの内部コマンドなので文字数制限(ARG_MAXの制限)を受けないためです。

また、xargsはARG_MAXの値を把握しているので、引数がARG_MAXを超えそうになると、自動的に複数回に分割して実行してくれるため、ARG_MAXの問題を回避することができます。

シェルのコマンド実行結果をパイプのようにコマンド引数として受け取る

コマンド実行結果の差分を取りたい場合など、
複数のパイプ処理をしたい場合、bash の < ( ... ) 構文を使うと便利です。

command < ( piped-command1 ) <(piped-command2 ) ...

例:

$ cat < (echo hello) <(echo world)
hello
world

ゴミ(一時ファイル)も作成されないのでエコロジーです。
 
例2: SJIS で書かれたテキストと UTF-8 で書かれたテキストを nkf で SJIS に統一して比較する。

$ diff $(nkf -Se index.shift_jis.html ) $(nkf -We index.utf8.html )

 
PHP で別々に処理した画像を imagemagick で結合する、という時や複数サーバから httpd ログファイルを拾ってきてマージする、なんていうときにも重宝します。
 
内部的にはファイルデスクリプタや FIFO を一時作成しています。
open(2) で開くことができるのでファイルを引数にとるプログラムなら大抵のもので使えますね。
 
検証:
Linux 2.6 の場合の実体はファイルデスクリプタ

$ ls -ld < ( echo foo )
lr-x—— 1 user user 64 8月 6 18:42 /dev/fd/63 -> pipe:[61042111]

FreeBSD 6 の場合は fifo (参考 mkfifo)

$ ls -ld < (echo foo)
prw——- 1 user wheel 0 8 6 19:04 /var/tmp//sh-np-2875720493

 
参考:
Can process substitution be used as an input file to another program?(The UNIX and Linux Forums)
zsh では =( … ) とのこと。

% cat =(echo hello)

みたいなかんじで。
一時ファイルを作らずにプログラムの出力を diff
diff の利用例。
Manpage of BASH

シェルで標準出力と標準エラー出力を入れ替える

$ command3>&2 2>&1 1>&3 | …

または

$ var=`command 3>&2 2>&1 1>&3`

とすると STDOUT と STDERR を入れ替えることが出来ます。

$ err=`grep “Tarou” address1 address2`
address1: Tarou 090-xxxx-xxxx
$ echo $err
grep: address2: No such file or directory

 
参考:
いずれもオンライン書籍です。
Swap Standard Output and Standard Error(UNIX POWER TOOLS)
I/O Redirection(Advanced Bash Shell Scripting Guide)

PHPで任意のファイルデスクリプタを開く

PHP には fdopen がないので、子プロセスについては /dev/fd/<FD番号> で代用してます。
PHP の機能ではありませんが。。

<?php
// child.php: 子プロセス(parent.php から実行される)
$fd = 4; // 親プロセスとのやり取りに使うファイルデスクリプタ(0:stdin, 1:stdout, 2:stderr)
$fdfile = “/dev/fd/$fd”;
if(!file_exists($fdfile)){
   die(“ファイルデスクリプタが開かれていません”);
}
 
$pipe = fopen($fdfile, “r”);
while(!feof($pipe)){
  echo fread($pipe, 1024);
}
fclose($pipe);

 

<?php
// parent.php: 親プロセス
$fd = 4; // 子プロセスとの通信に使うファイルデスクリプタ
$fp = proc_open(“php child.php”, array(
  $fd=>array(‘pipe’, r),
),$pipes);
 
fwrite($pipes[$fd], “Hello world!!”);
fclose($pipes[$fd]);
 
proc_close($fp);

 
FreeBSD の場合、標準では /dev/fd に 0,1,2 しかないため動作しません。
次のようにしてfdescfs を /dev/fd にマウントすればプロセスごとのファイルデスクリプタを自動作成してくれるようになります。

# echo “fdescfs /dev/fd fdescfs rw 0 0” >> /etc/fstab
# mount /dev/fd

または /dev/fd を使わない実装に置き換える事でも動作します。
この場合、ファイルデスクリプタが開いているかの確認には fstat [-p PID] を使うといいかもしれません。

// child.php: FreeBSD で devfs を使っている場合の代替実装。
$fd = 4;
$pipe = popen(‘cat < &'.$fd, 'r');
echo fread($pipe, 1024)
pclose();

Linuxの/proc 以下を見て、メモリ利用状況を調査する(OOM Killer対策)

oom-killer からメモリ関係を追っていて気になったのでメモ。
procファイルシステム配下のトップレベルファイル(redhat.com)
 
・ /proc/meminfo
現在のメモリの使用状況を表示します。
核パラメータの詳細はこちら(Linuxカーネルメモ)
例:

$ cat /proc/meminfo
MemTotal: 10391204 kB
MemFree: 5276876 kB
Buffers: 436432 kB
Cached: 3746096 kB
SwapCached: 0 kB
Active: 3976932 kB
Inactive: 757892 kB
HighTotal: 9567104 kB
HighFree: 5034592 kB
LowTotal: 824100 kB
LowFree: 242284 kB
SwapTotal: 8385920 kB
SwapFree: 8385920 kB
Dirty: 96 kB
Writeback: 112 kB
AnonPages: 467276 kB
Mapped: 884892 kB
Slab: 137352 kB
PageTables: 224292 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
CommitLimit: 13581520 kB
Committed_AS: 2113328 kB
HighTotal: 9567104 kB
HighFree: 5034592 kB
LowTotal: 824100 kB
LowFree: 242284 kB
SwapTotal: 8385920 kB
SwapFree: 8385920 kB
Dirty: 96 kB
Writeback: 112 kB
AnonPages: 467276 kB
Mapped: 884892 kB
Slab: 137352 kB
PageTables: 224292 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
CommitLimit: 13581520 kB
Committed_AS: 2113328 kB
VmallocTotal: 116728 kB
VmallocUsed: 6884 kB
VmallocChunk: 109344 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
Hugepagesize: 2048 kB

・ /proc/buddyinfo
 DMA, Normal, Highmem 領域ごとの空きメモリスロット(ページ単位)を表示します。
左から 1*4KB, 2*4KB, 4*4KB, 8*4KB, …, 4096*4KB(1ページ=4096バイトの場合) を1単位としたスロット数を表示していて、1行の合計がその領域の全空き容量になります。
例:

$ cat /proc/buddyinfo
Node 0, zone DMA 5 2 0 0 0 0 0 1 1 1 0
Node 0, zone Normal 209 104 20 5 2 1 0 0 1 1 0
Node 0, zone HighMem 6925 3038 1002 212 17508 8000 1164 274 118 9 633

 
・ /proc/zoneinfo
DMA, Normal, Highmem 領域ごとの詳細なメモリ使用状況を表示します。
例:

$ cat /proc/zoneinfo
Node 0, zone DMA // DMA 領域の情報(単位:ページ)
  pages free 905
        min 17
        low 21
        high 25
        active 2
        inactive 0
        scanned 0 (a: 21 i: 9)
        spanned 4096
        present 4096
・・・中略・・・
Node 0, zone Normal // Normal 領域の情報(単位:ページ)
  pages free 1305
        min 939
        low 1173
        high 1408
        active 625
        inactive 1889
        scanned 0 (a: 9 i: 0)
        spanned 225280
        present 225280
・・・以下略・・・

参考:
Linuxカーネルメモ

[Linux] procmailrc でひとつの条件に複数のアクションを指定する

同じ条件で複数指定すると簡単に実現できます。

 :0
 * 条件A
 * 条件B
 アクション1
 
 :0
 * 条件A
 * 条件B
 アクション2

が、同じ条件が分散するのは宜しくない、ということで。

 :0
 * 条件A
 * 条件B
 {
     :0
    アクション1
    :0
    アクション2
 }

このように括弧を使うと複数のレシピをひとつのアクションとして扱うことができます。
 
参考:
Procmail How-To page

Linuxでの常駐型サーバプログラムのデバッグ方法

http://kzk9.net/publications/webdb48/debug.html
常駐プロセスを作る時のはまりどころや、デバッグに役立つツールが紹介されています。実際に大規模システムで起こった経験に基づいていて大変参考になります。
 
– 関連
valgrind
google-perftools
Apache Thrift – 多言語 RPC フレームワーク