Bashプログラミング
 Computer >> コンピューター >  >> プログラミング >> Bashプログラミング

Marcel – Linux向けのよりモダンな新しいシェル

Marcelは新世代のシェルです。多くの点で従来のシェルと似ていますが、いくつかの点でまったく異なるアプローチを採用しています。

  • パイプ処理: 従来のシェルは、あるコマンドの出力を別のコマンドの入力へテキストとして渡すためにパイプを使います。一方Marcelは、文字列ではなく構造化データをパイプします。
  • Pythonとの統合: MarcelはPythonで実装されており、さまざまな形でPythonの機能を利用できます。コマンドにちょっとしたロジックが必要なときも、Pythonで自然に記述できます。
  • スクリプティング: Marcelはスクリプティングにユニークなアプローチを取っています。もちろん、marcelコマンドの並びをテキストファイルに書いて実行することもできますが、それだけではありません。MarcelはPythonモジュール形式のAPIも提供しており、これをインポートすれば、素のPythonよりもはるかに快適にスクリプトを書けます。

MarcelGPLv3ライセンスで公開されているオープンソースソフトウェアです。

LinuxへのMarcelのインストール方法

Marcelの動作にはPython 3.6以降が必要です。Linux上で開発・テストされており、macOSでもほぼ動作します(Windowsへの移植やmacOSの不具合修正に協力したい方は、開発者への連絡が歓迎されています)。

自分のユーザーアカウント向けにインストールする場合は、次のコマンドを実行します。

# python3 -m pip install marcel

システム全体で使えるようにインストールする場合(例:/usr/localへ)は、次のようにします。

$ sudo python3 -m pip install --prefix /usr/local marcel

インストールが完了したら、marcelコマンドを実行して動作を確認しましょう。marcelのプロンプトが表示されたら、versionコマンドでバージョンを確認できます。

$ marcel
Marcel – Linux向けのよりモダンな新しいシェル

Marcelシェルのカスタマイズ

marcelは~/.marcel.pyというファイルでカスタマイズできます。このファイルは起動時に読み込まれ、変更されれば自動的に再読み込みされます。ファイル名からも分かるように、カスタマイズはすべてPythonで行います。

プロンプトのカスタマイズ

まず試したくなるのがプロンプトの変更でしょう。PROMPT変数にリストを代入するだけで設定できます。例えば、「現在のディレクトリを緑色で表示し、その後に青色の>を続ける」プロンプトにしたい場合は、次のように書きます。

PROMPT = [
    Color(0, 4, 0),
    lambda: PWD,
    Color(0, 2, 5),
    '> '
]

実際の表示は次のようになります。

Marcel – Linux向けのよりモダンな新しいシェル

これだけで、bashで必要になる難解なPS1の設定を置き換えられます。Color(0, 4, 0)は緑色を意味し、引数は0〜5の範囲のRGB値です。PWDは現在のディレクトリを表す環境変数で、lambda:を付けることで関数化され、プロンプトが表示されるたびに評価されます。

Pythonモジュールのインポート

~/.marcel.pyではPythonモジュールをインポートすることもできます。例えば、mathモジュールの関数をmarcelコマンドで使いたい場合は次のようにします。

from math import *

これで、そのモジュールのシンボル(例:pi)を参照できるようになります。

Marcel – Linux向けのよりモダンな新しいシェル

piが括弧で囲まれている点に注目してください。marcelでは一般に、Python式を括弧で囲んで記述します。つまり(pi)は、変数piの値を取得するPython式として評価されます。同様の書き方で、(USER)(HOME)といった従来の環境変数にもアクセスでき、marcelの名前空間にあるシンボルを使った任意のPython式も記述できます。

独自の関数を定義する

もちろん、独自のシンボルや関数を定義することも可能です。例えば、次の関数定義を~/.marcel.pyに追加してみましょう。

def factorial(n):
    f = 1
    for i in range(1, n + 1):
        f *= i
    return f

これで、コマンドラインから直接factorial関数を呼び出せるようになります。

Marcel – Linux向けのよりモダンな新しいシェル

Marcelシェルのコマンド例

ここからは、marcelシェルでの具体的なコマンド例を見ていきましょう。

拡張子ごとのファイルサイズを集計する

現在のディレクトリを再帰的に探索し、ファイルを拡張子(.txt.pyなど)ごとにグループ化して、それぞれの合計サイズを計算してみます。

marcelなら、次のように一行で実現できます。

Marcel – Linux向けのよりモダンな新しいシェル

処理の流れは次のとおりです。

  • lsオペレーターがFileオブジェクトのストリームを生成します(-frは「ディレクトリを再帰的に辿り、ファイルのみを返す」という意味)。
  • Fileオブジェクトは次のmapオペレーターへパイプされます。mapは最も外側の括弧内にPython関数を受け取り、各ファイルを「拡張子とサイズ」のタプルに変換します(marcelではlambdaキーワードを省略できます)。
  • red(reduce)オペレーターが、タプルの最初の要素(拡張子)でグループ化し、各グループ内のサイズを合計します。結果は拡張子順にソートされます。

ホストの実行ファイルとMarcelパイプラインの混在

パイプラインには、marcelオペレーターとホスト側の実行ファイルを混在させられます。オペレーター同士はオブジェクトをやり取りしますが、オペレーターと実行ファイルの境界では、marcelは自動的に文字列へ変換して受け渡しします。

例えば、次のコマンドはオペレーターと実行ファイルを組み合わせて、ログインシェルが/bin/bashになっているユーザーのユーザー名を一覧表示します。

$ cat /etc/passwd \
| map (line: line.split(':')) \
| select (*line: line[-1] == '/bin/bash') \
| map (*line: line[0]) \
| xargs echo
Marcel – Linux向けのよりモダンな新しいシェル

catはLinuxの実行ファイルで、/etc/passwdを読み込みます。marcelはその内容を下流のmapオペレーターへパイプします。

  • mapの括弧内のPython関数は、各行を:で分割して7要素のタプルを生成します。
  • selectはmarcelオペレーターで、引数のPython関数によって「最後のフィールドが/bin/bashであるタプル」だけを選び出します。
  • 次のmapが、各タプルからユーザー名のフィールドを取り出します。
  • 最後にxargs echoが、受け取ったユーザー名を1行にまとめて標準出力へ出力します。

Marcelシェルでのスクリプティング

Pythonはしばしばスクリプト言語と呼ばれますが、実はシェル的な用途にはあまり向いていません。問題は、Pythonからシェルコマンドや外部プログラムを実行するのが面倒な点です。os.system()は手軽ですが、stdin・stdout・stderrの扱いには不十分なことが多く、subprocess.Popen()は強力な反面、コードが複雑になりがちです。

Marcelのアプローチは、marcelオペレーターをPythonの言語機能と統合したモジュールを提供することです。先ほどの「拡張子ごとのファイルサイズ集計」をPythonで書くと、次のようになります。

from marcel.api import *

for ext, size in (ls(file=True, recursive=True)
                  | map(lambda f: (f.suffix, f.size))
                  | red('.', '+')):
    print(f'{ext}: {size}')

シェル版のコマンドと構文の表記以外は同一です。ls -frls(file=True, recursive=True)に対応し、mapやredもシェル版と同じくパイプ(|)で接続されています。パイプライン全体(ls … red)はPythonのイテレータを返すため、そのままforループで回せます。

Marcelシェルからのデータベースアクセス

marcelのパイプラインには、データベースアクセスも組み込めます。まず、設定ファイル~/.marcel.pyでデータベースへの接続情報を定義します。

define_db(name='jao',
          driver='psycopg2',
          dbname='acme',
          user='jao')

DB_DEFAULT = 'jao'

この例では、psycopg2ドライバー経由でacmeというPostgresデータベースへのアクセスを設定しています。接続にはjaoユーザーが使われ、このプロファイルはjaoという名前で登録されます(DB_DEFAULTは、プロファイルの指定がない場合に使われるデフォルトを指定します)。設定が済めば、sqlオペレーターでデータベースをクエリできます。

sql 'select part_name, quantity from part where quantity < 10' \
| out --csv –-file ~/reorder.csv

このコマンドはpartテーブルを検索し、結果をCSV形式で~/reorder.csvに出力します。

Marcelシェルでのリモートアクセス

データベースと同様に、リモートホストへのアクセスも~/.marcel.pyで設定できます。例えば、4ノードのクラスタを定義するには次のように書きます。

define_remote(name='lab',
              user='frankenstein',
              identity='/home/frankenstein/.ssh/id_rsa',
              host=['10.0.0.100', 
                    '10.0.0.101',
                    '10.0.0.102',
                    '10.0.0.103'])

これで、marcelコマンド内ではこのクラスタをlabという名前で参照できます。userとidentityパラメータはSSHログイン情報を、hostパラメータはクラスタを構成するノードのIPアドレスを指定します。

クラスタを設定しておけば、全ノードに対して一度に操作を実行できます。例えば、クラスタ全体のプロセスIDとコマンドラインの一覧を取得するには、次のようにします。

@lab [ps | map (proc: (proc.pid, proc.commandline))]

このコマンドは、「IPアドレス・PID・コマンドライン」のタプルからなるストリームを返します。

まとめ

詳細については、以下の公式サイトやGitHubリポジトリをご覧ください。

Marcelは登場して間もないプロジェクトで、現在も活発に開発が進められています。開発に協力したい方は、ぜひ開発者に連絡してみてください。

  1. Linuxシェルスクリプトで学ぶ数学処理 – 第4回:四則演算から素数判定まで

    今回は、数学と数値計算の視点からシェルスクリプトを学んでいきます。前回の記事ではやや複雑なスクリプト(簡易電卓)を紹介しましたが、読者にとっては少し理解しづらかったかもしれません。そこで今回は、内容を小さな単位に分割し、シェルスクリプトのもうひとつの実用的な側面を段階的に習得できるよう構成しました。 これまでの連載記事 この記事までに公開されているシェルスクリプト入門シリーズは以下の3本です。まだお読みでない方は、先に目を通しておくと理解がより深まります。 Linuxシェルと基本のシェルスクリプトを理解する – 第1回 シェルプログラミングが学べる5つのシェルスクリプト – 第2回 Linu

  2. Linux初心者・管理者必見!無料で読めるシェルスクリプト電子書籍4選

    システム管理とは何か システム管理(System Administration)は情報技術(IT)の一分野であり、マルチユーザーのコンピュータシステムやサーバーを安定的に稼働させ続けることを担います。この安定稼働に責任を持つ人物をシステム管理者(System Administrator)と呼びます。 専門分野がLinuxであるシステム管理者は「Linuxシステム管理者」と呼ばれます。その役割は非常に多岐にわたり、ハードウェアの保守、システムメンテナンス、ユーザー管理、ネットワーク管理、システムパフォーマンスの監視、リソース使用状況のモニタリング、バックアップ、セキュリティの確保、システム更新、