4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

シェルスクリプト&PowerShellAdvent Calendar 2023

Day 5

シェルスクリプト用のファイル名・拡張子取得・パス正規化ライブラリ

Last updated at Posted at 2023-12-04

はじめに

シェルスクリプト用のファイル名・拡張子取得・パス正規化ライブラリ「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 シェルの機能だけで動くようにして、最低限のテストを付け加えただけなので、テストが甘いかもしれません。将来的に総合的なシェルスクリプト用の標準ライブラリを作る予定なので、それまでのつなぎとして機能の一部の先行リリース扱いです。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?