Linux使いならlsを使わない日はないだろう。
lsのオプションで大体-lをつける人が多いかもしれないが、
たまにはlsでオプションをつけない奴も実行してみてほしい。
ちょっと不思議な動作をしている。
$ls foobar1 foobar2 foobar4 foobar6 foobar8 foobardasdadada foobar10 foobar3 foobar5 foobar7 foobar9
上記のようにlsだけを打てば横にずらずらと書かれる
一方で、おなじくオプションをつけないlsの結果をリダイレクトをすると、ファイルが一つずつ改行されて表示される。
$ls > foobar.txt $cat foobar.txt foobar.txt foobar1 foobar10 foobar2 foobar3 foobar4 foobar5 foobar6 foobar7 foobar8 foobar9 foobardasdadada $
コンソールに出力されているものと、リダイレクトされるもので内容が変わっている
リダイレクトとパイプが改行で区切られるようになっている
ファイルが一つずつ改行されるモードはオプションでは-1というものがある。
数字の1だ。
ls -1 で実行すると一つずつ改行される。
リダイレクトされた内容はまさにそれと同じものだった。
$ls | hexdump -C 00000000 66 6f 6f 62 61 72 2e 74 78 74 0a 66 6f 6f 62 61 |foobar.txt.fooba| 00000010 72 31 0a 66 6f 6f 62 61 72 31 30 0a 66 6f 6f 62 |r1.foobar10.foob| 00000020 61 72 32 0a 66 6f 6f 62 61 72 33 0a 66 6f 6f 62 |ar2.foobar3.foob| 00000030 61 72 34 0a 66 6f 6f 62 61 72 35 0a 66 6f 6f 62 |ar4.foobar5.foob| 00000040 61 72 36 0a 66 6f 6f 62 61 72 37 0a 66 6f 6f 62 |ar6.foobar7.foob| 00000050 61 72 38 0a 66 6f 6f 62 61 72 39 0a 66 6f 6f 62 |ar8.foobar9.foob| 00000060 61 72 64 61 73 64 61 64 61 64 61 0a |ardasdadada.|
パイプで値を渡してみる。
上記の場合はパイプでhexdumpコマンドに渡して、内容を表示するようにした。
すると、ところどころに0aという値が入っている。
これは改行コードのlfを表している。
つまり、コンソールと、リダイレクト・パイプがそれぞれ内容がちがう出力をしている
lsのソースに答えを求めた
ああだこうだ色々考えても仕方がない。
我らLinuxとそのGnuツール群はオープンソースなのだから、
動作に気になるところがあれば、ソースを見ればいい
githubが正ではないみたいだが、ミラーみたいな扱いとしてgithubでも公開されていた。
https://github.com/coreutils/coreutils
src/ls.c にlsのソースがある。
出力先の判定をしているところを見つけた
僕はC言語を使える人間ではないので、それっぽいところから探していく。
decode_switches関数付近にそれらしい処理を見つけた。
case LS_LS: /* This is for the 'ls' program. */ if (isatty (STDOUT_FILENO)) { format = many_per_line; set_quoting_style (NULL, shell_escape_quoting_style); /* See description of qmark_funny_chars, above. */ qmark_funny_chars = true; } else { format = one_per_line; qmark_funny_chars = false; } break;
one_per_lineとは、一行につき一つという意味で、もう一つのmany_per_lineとは一行につき沢山って意味だろう。
one_per_lineは-1オプションをつけたときに有効になるようなので、
まさにファイル一つずつに改行モードを示している
case '1': /* -1 has no effect after -l. */ if (format != long_format) format = one_per_line; break;
つまり以下の部分で、改行を入れるモードの制御を行っているということだ。
if (isatty (STDOUT_FILENO)) { format = many_per_line; set_quoting_style (NULL, shell_escape_quoting_style); /* See description of qmark_funny_chars, above. */ qmark_funny_chars = true; } else
isatty (STDOUT_FILENO) という関数で何が行われるのか。
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/isatty.3.html
ここのページでみてみると、
ファイルディスクリプターが端末を参照しているかどうかを調べてくれるらしい。
なんのこっちゃわからない説明だ。
http://x68000.q-e-d.net/~68user/unix/pickup?isatty
こちらのページをみてみると、出力がコンソールかパイプかがわかるという例でほぼ同じコードが載っている。
つまり、isattyでコンソールかパイプかを振り分けて、出力結果を変えているのだ。