はじめに
シェルスクリプト用のファイル名・拡張子取得・パス正規化ライブラリ「sh-path」を作りました。シェルスクリプト用のコマンドにディレクトリ名を取得する dirname
コマンドとファイル名を取得する basename
コマンドがありますが実際の用途ではこれだけでは足りません。拡張子を取り除いたり取得する方法が(簡単では)なかったり、相対パスが含まれているパスを正規化したり、相対パスと絶対パスを変換するコマンドが欠けています。
また dirname
コマンドや basename
コマンドは機能不足で、外部コマンドなので遅い、オプションと見なされないように --
が必要、コマンド置換を使うから末尾の改行が消えてしまうなどの細かい問題があります。このライブラリはそういった細かい問題を解決しています。
関数一覧
基本的には他の言語のライブラリを参考に開発しており、どこかで見たような名前と機能のシェル関数なのでそんなに迷うことはないでしょう。
関数名 | 機能 |
---|---|
path_dirname |
ディレクトリ名の取得(dirname コマンド相当) |
path_basename |
ファイル名の取得(basename コマンド相当) |
path_extname |
拡張子の取得 |
path_rootname |
拡張子を取り除く(ディレクトリとファイル名のみ残す) |
path_normalize |
パスの正規化を行い絶対パスに変換する |
path_relative |
絶対パスを相対パスに変換する |
使い方は dirname
コマンドや basename
コマンドと違い、第一引数に指定した変数名に戻り値を返します。これはコマンド置換をさけることでパフォーマンスの改善と末尾の改行が消えなくするための工夫です。
# 一般的なコマンドの使い方
dir=$(dirname -- /home/koichi/.bashrc)
echo "$dir" # => /home/koichi
base=$(basename -- /home/koichi/.bashrc)
echo "$base" # => .bashrc
# sh-pathの使い方
path_dirname dir /home/koichi/.bashrc
echo "$dir" # => /home/koichi
path_basename base /home/koichi/.bashrc
echo "$base" # => .bashrc
拡張子の取得や拡張子の削除を行うときに、サフィックスを指定することができます。使い方はおそらく例を見たほうが早いでしょう。特徴として .tar.gz
のような多重の拡張子にも対応しています。
path_extname ret "/var/tmp/file.tar.gz" .tar
echo "$ret" # => なし
path_extname ret "/var/tmp/file.tar.gz" .gz
echo "$ret" # => .gz
path_extname ret "/var/tmp/file.tar.gz" .tar.gz
echo "$ret" # => .tar.gz
path_extname ret "/var/tmp/file.tar.gz" ".*.*"
echo "$ret" # => .tar.gz
path_extname ret "/var/tmp/file.tar.gz" ".**"
echo "$ret" # => .tar.gz
ソースコードは例(?)のグローバル変数を使わずに POSIX シェルの機能だけで実現するために位置パラメータを多用しているので読みづらいです。だからこそ短く書いているので読めないと言うほどでもないと思います。
制限
現在 BusyBox for Windows (busybox-w32) には対応していません。busybox-w32 のパスは Windows のパスと同じで C:\Windows
や '\\server\koichi'
のようなパスが使えて対応が面倒なんですよ・・・。そのうち気が向いたら対応しますがコードは完全に分離しそうな気がしています。
関数
関数ごとの使い方と例です。
path_dirname
Usage: path_dirname varname pathname
varname: variable name
pathname: path name
path_dirname ret "/var/tmp/file.txt"
echo "$ret" # => /var/tmp
path_basename
Usage: path_basename varname pathname [suffix]
varname: variable name
pathname: path name
suffix: .*, .*.*, .**, .ext (default: NULL)
path_basename ret "/var/tmp/file.txt"
echo "$ret" # => file.txt
path_extname
Usage: path_extname varname pathname [suffix]
varname: variable name
pathname: path name
suffix: .*, .*.*, .**, .ext (default: .*)
path_extname ret "/var/tmp/file.txt"
echo "$ret" # => .txt
path_rootname
Usage: path_rootname varname pathname [suffix]
varname: variable name
pathname: path name
suffix: .*, .*.*, .**, .ext (default: .*)
path_rootname ret "/var/tmp/file.txt"
echo "$ret" # => /var/tmp/file
path_normalize
Usage: path_normalize varname pathname [basedir]
varname: variable name
pathname: path name
basedir: base directory (default: PWD)
path_normalize ret "/var///tmp/.././file.txt"
echo "$ret" # => /var/file.txt
path_relative
Usage: path_relative varname pathname [basedir]
varname: variable name
pathname: path name
basedir: base directory (default: PWD)
path_relative ret "/var/tmp/file.txt" /var/
echo "$ret" # => ./tmp/file.txt
さいごに
かなり昔に bash 専用で書いたコードを掘り起こして、拡張子周りの機能を追加して、POSIX シェルの機能だけで動くようにして、最低限のテストを付け加えただけなので、テストが甘いかもしれません。将来的に総合的なシェルスクリプト用の標準ライブラリを作る予定なので、それまでのつなぎとして機能の一部の先行リリース扱いです。