Shellの機能を拡張する方法
- bashの新機能は非常に便利です。
- この記事では、バージョン4.0以降で追加された新しい機能について紹介します。
- shellscriptの互換性について考慮する際には、新しい機能を追加する際に慎重である必要がありますが、使用しなくても知っておくことは有益です。
これらの新機能がどのような問題を解決するために追加されたのかを見ていきましょう。
2016年9月、bashのバージョンが4.4にアップデートされ、多くの新機能が追加されました。しかし、bashをアップデートするたびにあまり興味が湧かない理由があります。例えば、bashスクリプトをPOSIX標準に合わせると、bashの新機能がいくつかのセキュリティリスクを生むことが分かります(*1)。一方で、コマンドラインを使ってシェル操作を行う場合、パイプやリダイレクトを多く使います。新機能が追加されたものの、どこか少し物足りない感じがするのです。
新機能にはそれぞれ理由があるのですが、その中でも一部の人々は、bashの新機能が必要だと感じ、その追加を支持しています。
さらに、bash内でデータやフラグの管理を見えなくするための新しい機能があることがわかりました。たとえ使わない機能でも、それを理解することによって、シェルの仕組みをより深く知ることができます。そのため、この記事では、バージョン4.0以降のbashに追加された新機能に焦点を当て、これらの機能がどのような問題を解決するために追加されたのか、またその便利さについて深掘りしていきます。
bash 4.4の準備
bashのコードは[https://ftp.gnu.org/gnu/bash/](https://ftp.gnu.org/gnu/bash/)から入手できるので、バージョン4.4をダウンロードして使用しましょう。ほとんどのUNIX系のOSでは、手動でインストールできます。詳細なインストール方法は[指示1]に記載されています。以前のバージョンについても同様の方法でインストールできますので、古いバージョンと新しいバージョンを比較する際は、[指示1]の手順を調整してみてください。この記事では、Ubuntu 16.04 Server環境で動作確認を行いました。
各バージョンでの変更内容は、tarで展開したCHANGESファイルに記録されています。興味がある方はぜひ確認してみてください。
また、bashをバージョンアップした際には、BASH_VERSION環境変数を頻繁に確認しましょう。例えば、バージョン4.4と3.2をPATHに設定し、次のように切り替えてみてください。
$ bash4.4
$ echo $BASH_VERSION
$ 4.4.0(1)-release
$ bash3.2
$ echo $BASH_VERSION
$ 3.2.57(1)-release
標準出力と標準エラー出力の統合とパイプ「|&」の使用
まずは簡単なトピックから始めましょう。バージョン4.0以降、bashでは|&がパイプの新しいシンボルとして導入されました。bashを使っているとき、標準出力と標準エラー出力を統合した後、別のコマンドに渡したいことがありますが、バージョン3.2までは以下のように書かなければなりませんでした:
$ ls a aa 2>&1 l nl
1 ls: 'aa'にアクセスできません:省略された部分
2 a
上記のコードでは、標準エラー出力と標準出力を統合してパイプに渡し、nlコマンドで番号を付けています。しかし、バージョン4.0以降では、以下のように書くことができ、簡潔に処理ができます。
$ ls a aa l& ln
1 ls: 'aa'にアクセスできません:省略された部分
2 a
これにより、書き方が簡単になり、効率的になります。しかし、単に書き換えたことで新しい機能が追加されたわけではありません。便利さを感じるかどうかは使用状況に依存します。次に、findコマンドをディレクトリで実行する例を見てみましょう。標準出力と標準エラー出力がどのように扱われるか確認できます。
$ find /proc/
/proc/
/proc/fb
(..省略..)
find: `/proc/tty/driver': 許可がありません
find: `/proc/1/task/1/fd': 許可がありません
(..省略..)
【指示1】bashのインストール方法
$ wget https://ftp.gnu.org/gnu/bash/bash-4.4.tar.gz
$ tar zxvf bash-4.4.tar.gz
$ cd bash-4.4/
$ ./configure && make -j
$ sudo cp bash /usr/local/bin/bash4.4
$ bash4.4 --version
GNU bash, バージョン 4.4.0(1)-release (x86_64-unknown-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
ライセンスはGPLv3+:GNU GPL バージョン3以上
これは自由ソフトウェアです。変更および再配布が可能です。
法的に許可される限り、保証はありません。
もしfindコマンドを使わず、標準出力と標準エラー出力をファイルにリダイレクトしたい場合は、以下のようにできます。
$ find /proc/ 2> /dev/null
↑ 標準出力のみ表示
$ find /proc/ > /dev/null
↑ エラーのみ表示
または:
$ find /proc/ > a 2> b
上記のようにして、1回の操作でファイルにまとめて表示できます。これを使うと、パイプで簡単に標準出力とエラー出力を同時に扱うことができます。
$ find /proc l& less
↑ 両方を表示
$ find /proc l& grep ^find: | less
↑ エラーのみ表示
$ find /proc l& grep -v ^find: | less
↑ 標準出力のみ表示
これにより、不要な一時ファイルを作成せずに、標準出力とエラー出力を分けて表示できます。`|&`が無ければ、ファイルを作成せざるを得ませんが、`|&`を使うとこれを回避できます。
次に紹介するのは「>>」という記号です。これは標準出力と標準エラー出力を統合し、それをファイルに追記するために使います。
$ ls a b &> result
↑ 標準出力と標準エラー出力を統合してリダイレクト
$ ls a b &>> result
↑ 追記として標準出力と標準エラー出力をリダイレクト
$ cat result
ls: 'a'にアクセスできません:省略された部分
b
ls: 'a'にアクセスできません:省略された部分
b
(*1) shで記述してもbash環境で実行する場合は、bashの環境が問題となることがあります。
$ ls a b &> result
↑ 標準出力とエラー出力をまとめてファイルに保存
$ ls a b &>> result
↑ 標準出力とエラー出力をファイルに追記
$ cat result
ls: 'a'にアクセスできません:省略された部分
b
ls: 'a'にアクセスできません:省略された部分
b