1 ポイント 投稿者 GN⁺ 2024-07-30 | 1件のコメント | WhatsAppで共有
  • izabera/ps は、新しいプロセスを作れない状況でも Bash の中で ps aux に近い出力を再現するための Bash 実装 です
  • 中核となる前提条件は、ssh で接続したマシンに信頼できる bash shell はあるものの、ほかの PID がすべて使用中で新しいプロセスを生成できない状況です
  • README はこの状況を、Bash/Linux の知識が必要なポジション向けの 面接質問 の例として提示しています
  • このツールは「動く ps aux にアクセスできるふり」をできるようにすると表現されており、完全な代替実装であることを保証していません
  • 「すべてのマシンとあらゆる状況で 100% 動作する」という文は、明らかな ジョークめいた保証 として使われています

これは何をするプロジェクトか

  • ps auxBash だけで 書いたプロジェクトです
  • README のタイトルは「ps aux written entirely in bash without ever forking」です
  • プロジェクトの中心的な特徴は、実行中に fork をまったく行わない点です

想定している状況

  • 例として挙げられている状況は次のとおりです
    • ssh でマシンに接続している
    • ユーザーは使い慣れた bash shell の中にいる
    • しかし、ほかの PID がすべて使われており、新しいプロセスをまったく生成できない
  • README では、この条件下で ps aux に似た機能が必要になるかもしれないと紹介しています

期待できる範囲と caveat

  • このツールは、動作する ps aux があるかのように "kinda sorta pretend" できるようにする用途として紹介されています
  • README の「100% のマシンであらゆる状況において完璧に動作、保証」という文言は、誇張された ユーモア として使われています
  • したがって説明上の要点は、完全な互換性よりも、新しいプロセスを作れない極限環境で Bash だけを使って ps aux を再現することにあります

1件のコメント

 
GN⁺ 2024-07-30
Hacker News のコメント
  • コンピュータサイエンスで一番難しい問題は結局 桁揃えだった、という冗談が妙に刺さる
    いろいろな言語で列を揃える関数を数え切れないほど書いてきたが、毎回つらかったし、頭の中では「各列の最大長を求めて、タブ幅の次の倍数まで空白を入れればいい」くらい単純に見える
    Python の f-string とパディング機能を使っても、コードはすぐ複雑で読みにくくなり、コメント用の例を書き直している最中にもバグをいくつも直したほどひどい

    • きれいな表を出力するために、こういうコードを自分で書きたくなくてプロジェクトに Pandas を追加したこともある
      これほど一般的な用途なら当然ライブラリがあるはずだし、正直、標準ライブラリにないのは驚き
    • https://perldoc.perl.org/perlform
    • 以前 Stack Overflow で O(n) の解法として回答したことがある: https://stackoverflow.com/questions/10865483/print-results-i...
      データベースカーソルの description から列幅と名前を取り出し、区切り線とフォーマット文字列を作ってから行を出力する方式だが、何か見落としている致命的なバグがあるのかは分からないし、特に難しい問題には見えない
    • もっと単純には、zip(*table) で列を転置して各列の最大長を求めた後、f"{r:<{w}}" で揃えて出力できる
      例の結果は agony | kick | pump のように列幅が揃った表になる
    • 逆に、列揃えされたデータのパースを頻繁にしなければならない立場からすると、これも簡単ではない
      値の中に空白が入り、空白でパディングされていて、ときどき揃えが崩れ、列からはみ出すこともある
      いっそ互いに取り決めて、列揃えデータは使わず、もっと単純で人間が読める形式を使ったほうが全員にとって得になりそう
  • SSH で入ったマシンで Bash シェルは生きているのに全 PID が使い尽くされて新しいプロセスを作れないなら、/proc/[pid]/ ファイルシステムを探って、どのプロセスが PID 空間を枯渇させているのか確認すると思う
    Bash の kill はシェル組み込みコマンドなので、/bin/kill のように新しいプロセスを fork する必要がない
    PID を枯渇させる子プロセスを生み出している親プロセスを見つけられれば、それを止めてシステムの制御を取り戻せる
    このスクリプトも /proc をパースしていて、新しい Bash サブシェルを作り得るパイプや $(...) 置換もなく、かなりすっきりしている

    • 面接で「exec Python」と答えたことがある
      そうすれば別コマンドを実行しなくても必要な POSIX 関数を呼び出せるので、好反応だった
    • 正直、自分なら単に 再起動すると思う
      制限された環境で親プロセスを探して kill するより、再起動して復旧するほうが速いかもしれないし、PID が尽きているなら他の部分もすでに悪い状態になっている可能性が高い
    • PID とコマンド名だけ見たいなら、ほぼ最小形でこうもできる: ps(){ (cd /proc;for i in [0-9]*;do echo $i: $(tr '\0' ' ' < $i/cmdline);done); }
    • /proc/[pid]/ でどのプロセスが PID 空間を枯渇させているかを見るというのは正しいが、ソースコードのコメントを見ると、最初は /proc/*/status だけで十分であることを期待していたものの、CPU 使用率のような値はそこから取得できなかったと書かれている
    • サブプロセス関連で、[[ $cmdline ]] && exec {cmdline}>&-exec {cmdline}< "$dir"/cmdline || continue がどう動くのか、本気で気になる
  • 2011 年に米国のかなり大きなテック企業で SRE ロールの面接を受けたが、当時は SRE という用語も初めて聞いた
    その会社はブラウザベースの MS Office 代替を作っていて、電話スクリーニングの後は、同社の文書エディタ内で面接官と通話しながらリアルタイムにプログラミングしなければならなかった
    自己評価表で shell scriptingLinux を高めに書いて出したため、Bash で netstat の代替を作る課題を受けたが、当時はソケット情報が /proc/ のどこにどうあるのか分からず、すぐに無理だと判断した
    代わりに縮小版の psfuser を作ると提案し、あのひどいブラウザベースのワープロ内で出した解法が受け入れられてオンサイト面接まで進んだ
    今思うと、この練習問題の動機になっていた仮想シナリオは、思った以上に現実に根差していたのかもしれない

    • こうしたシステムユーティリティの一部は、どうせ内部で procfs/sysfs を覗いている可能性が高い
      自分でもそこから始めると思う
  • SSH で入った状態で新しいプロセスを作れない状況を探索する インタラクティブな Web サイトを、以前遊びで作った: https://oops.cmdchallenge.com

    • "echo *" はディレクトリ内のすべてのファイルを列挙しない
      "echo .* *" を使う必要がある
    • かっこいいのだが、クリアしたら最初のステージに戻ってしまい、他のステージを見られなくて歯がゆかった
      他のステージの "View Solutions" 一覧を見て、どんな別アプローチが可能だったのか確認したかった
  • Izabera は #bash@libera の達人の一人
    昔の freenode 時代から、そういう達人たちにはこの 10 年で本当に多くを学んだ

  • これはかなり きれいな Bash
    経験上、Bash コードはたいていひどく書かれていて非効率なことが多いが、このコードはそうではない良い例に見える

    • きれいな Bash なら移植性もあるべきだが、このスクリプトは Linux 専用で、他の場所ではひどく壊れるだろう
  • Bash サポートのない信頼できる POSIX シェルに入っている場合はどうすればいいのか?
    この Bash スクリプトは POSIX 互換ではない

  • このスクリプトは Bash 3.2 では動かないが、Bash 4.2 では動作する
    Bash 3.2 では printf: '(': invalid format character エラーが出て、例の環境は bash-3.2-33.el5_11.4.0.1 である

    • 18 年前の Bash リリース系列と 17 年前の OS リリース系列をサポートしないのは十分に合理的だと思う
  • より良い用途は、procps がインストールされていないシステムでプロセス一覧を見ることかもしれない
    悪くない

  • Bash で リスナーとクライアントも作ることはできる
    実戦ではおすすめしない