LinuxLinux [リナックス / ライナックス]オープンソースのOSカーネルでファイルパスを扱っているとき、「ディレクトリのパス部分は不要で、ファイル名だけを取り出したい」あるいは「ファイルの拡張子を外して名前だけ取得したい」というケースはよくあります。
そのようなときに便利なのが basename コマンドです。本記事では、basenameコマンドの基本的な使い方から、拡張子を削除するオプション、そしてシェルスクリプトでの実践的な活用例までをわかりやすく解説します。
basenameコマンドとは?
basename コマンドは、指定されたパス文字列からディレクトリ部分を取り除き、最後のファイル名(またはディレクトリ名)のみを抽出して表示するコマンドです。
逆に、パス文字列からディレクトリ部分だけを抽出する dirname というコマンドもあり、これらはシェルスクリプトなどでセットでよく使われます。
basenameコマンドの基本的な使い方
ターミナルで basename コマンドの後にファイルパスを指定して実行します。
basename [パス]パスからファイル名だけを抽出する
例えば、/usr/local/bin/python3 というパスから python3 というファイル名だけを取り出したい場合は、以下のように実行します。
basename /usr/local/bin/python3python3パスの中にスラッシュ / が含まれている場合、最後の / より前の部分(ディレクトリのパス)がすべて削除され、末尾の文字列だけが出力されます。
※注意点
basenameコマンドは、指定された文字列を処理しているだけです。指定したパスのファイルが実際に存在するかどうかは確認しません。 適当な架空のパスを渡しても、単に文字列として処理されて結果が返ってきます。
拡張子(サフィックス)を取り除く方法
basename コマンドは、ファイル名から特定の拡張子(サフィックス)を取り除くことも可能です。主に以下の2つの方法があります。
方法1:引数で拡張子を指定する
パスの後に、削除したい拡張子(サフィックス)の文字列を指定します。
basename /home/tsuka/example.c .cexamplebasename /backup/archive.tar.gz .gzarchive.tar末尾が .gz と一致した場合、その部分が削除されます。もしファイル名の末尾が指定した文字列と一致しない場合は、拡張子は削除されず、ファイル名がそのまま出力されます。
※Tips(複合拡張子への対応)
.tar.gzのような複合拡張子を完全に除去したい場合、上記のように.gzだけを指定するとarchive.tarのように.tarが残ってしまいます。 これを完全にarchiveだけにするには、basename file.tar.gz .tar.gzのように複合拡張子全体を指定するか、2段階で処理する必要があります(より柔軟に処理したい場合は後述の変数展開${filename%%.*}が便利です)。
方法2:-s(—suffix)オプションを使う
-s オプションを使って削除したい拡張子を指定することもできます。こちらの書き方の方が、オプションであることが明確になるためスクリプトなどで好まれることがあります。
basename -s .txt /home/user/document.txtdocument※補足(-s オプションと複数パス指定)
-sオプションを使用すると、内部的に後述の-a(複数パス処理)オプションが暗黙的に有効になります。そのため、-sを使った場合は複数のファイルパスを並べて指定し、一括で拡張子を削除することも可能です。実行例 basename -s .txt file1.txt file2.txt実行結果 file1file2
複数のパスをまとめて処理する(-aオプション)
-a(--multiple)オプションを使用すると、複数のパスを一度に渡して、それぞれの basename を取得することができます。
basename -a /home/user/test.txt /var/log/auth.logtest.txtauth.log※注意(一部のBSD環境でのポータビリティ)
-aオプションは GNU版のbasename(一般的なLinux環境)や近年のmacOSmacOS [マックオーエス]Appleが開発するMac用のオペレーティングシステムには実装されていますが、NetBSDなど一部のBSD系OSOS [オーエス]Operating System。基本ソフトウェアのbasenameではサポートされていないことがあります。どの UNIX/Linux 環境でも確実に動くポータブルなスクリプトを書きたい場合は、-aを避け、古典的なforループで1つずつ処理する方が安全です。
シェルスクリプトでの実践的な活用例
basename コマンドは、ターミナルで手動で叩くよりも、シェルスクリプトの中で変数と組み合わせて使われることが圧倒的に多いです。
1. 実行中のスクリプト名を取得する
シェルスクリプト自身のファイル名を取得する際によく使われます。$0 にはスクリプトの実行パスが入っているため、そこからスクリプト名だけを抽出します。
#!/bin/bash
# $0 は実行パス(例: ./script_name.sh や /path/to/script_name.sh)SCRIPT_NAME=$(basename "$0")
echo "このスクリプトの名前は ${SCRIPT_NAME} です。"※重要(パスにスペースが含まれる場合の対策)
実務において、パスにスペースが含まれている(例:My Documents)ケースはよくあります。シェルスクリプトで変数に入ったパスをbasenameに渡す際は、必ず ダブルクォーテーションで囲む(例:basename "$filepath")ようにしてください。囲まないと、スペースの部分で引数が分割されてしまい、予期せぬエラーやバグの温床となります。
2. ファイルの拡張子を一括で変換する
例えば、特定のディレクトリ内にある .jpeg ファイルの拡張子をすべて .jpg に変更したい場合、ループ処理の中で basename を使うことができます。
#!/bin/bash
for file in *.jpeg; do # 拡張子 .jpeg を除いたファイル名を取得 name=$(basename "$file" .jpeg)
# 新しい拡張子 .jpg をつけてリネーム mv "$file" "${name}.jpg"done※補足と技術的な落とし穴(変数展開との違い)
Bashの変数展開(${file%.jpeg}や、ファイル名取得のための${path##*/}など)を使うことでも同じような処理が可能です。変数展開の方が外部コマンドを呼び出さない分高速ですが、末尾にスラッシュが含まれるパスを扱う際の挙動に決定的な違いがあります。
basenameコマンド:basename /var/log/httpd/のように末尾にスラッシュがあっても、適切に無視(除去)してhttpdを返してくれます。- 変数展開 (
${path##*/}): 最長一致で最後のスラッシュ以降を取り出そうとするため、末尾がスラッシュだと空文字になってしまい、正しくファイル名を取得できません。パスの末尾にスラッシュが入る可能性がある場合は、安全のために
basenameコマンドを使うか、丁寧な事前処理が必要です。また、シェルに依存しないポータブルなスクリプトを書きたい場合にもbasenameコマンドが好まれます。
関連コマンド:dirname
basename の逆の働きをするのが dirname コマンドです。パスからファイル名を取り除き、ディレクトリ部分だけを出力します。
dirname /usr/local/bin/python3/usr/local/binスクリプトが置かれているディレクトリパスを取得したい場合などに、basename と同様によく使われます。
まとめ
basename コマンドのポイントは以下の通りです。
- パス文字列からディレクトリ部分を削除し、ファイル名だけを抽出する。
- 拡張子を指定することで、ファイル名から特定の拡張子を取り除くことができる(例:
basename file.txt .txtや-sオプション)。 - 実際のファイルの存在有無はチェックせず、単なる文字列処理として動作する。
- シェルスクリプトの中で
$0からスクリプト名を取得したり、ファイル名を一括置換するループ処理で非常に活躍する。
ディレクトリパスを取得する dirname コマンドとセットで覚えておくと、Linuxでのファイル操作やスクリプト作成が格段にスムーズになります。
以上で本記事の解説を終わります。
よいITライフを!
人気記事
- 1
- 2
- 3
- 4
- 5
Rocky Linux対応。実際にWebサーバーを公開するまでのプロセスを体験できる、最も確実で実践的なガイドブックです。