宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
「シェルスクリプトでファイルパスからファイル名だけ取り出したい」
「ディレクトリ部分だけを変数に入れて処理したいが、sedやawkでのパス加工は複雑すぎる」
サーバー運用の現場でシェルスクリプトを書いていると、フルパスからファイル名や親ディレクトリを取り出す操作は日常茶飯事です。そのたびに正規表現を書いていては効率が悪く、バグの温床にもなります。

この記事では、basename(ベースネーム)dirname(ダーネーム) コマンドの実践的な使い方を解説します。
基本的なパス分解から、拡張子の除去、for ループや find との組み合わせ、スクリプト内での自己パス取得まで、20年以上Linuxサーバーを運用してきた経験から、現場で実際に使えるパターンをまとめました。

動作確認環境:RHEL 9.4 / Ubuntu 24.04 LTS

この記事のポイント

・basename はパスの最後の要素(ファイル名)を取り出す
・dirname はパスのディレクトリ部分を取り出す
・basename に拡張子を指定すると拡張子なしのファイル名を得られる
・スクリプト内の自己パス取得には dirname "$0" が定番


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

basename と dirname の役割を理解する

シェルスクリプトでパスを扱う際、basenamedirname は対になるコマンドです。

たとえば /var/log/httpd/access_log というパスに対して:

basename:パスの末尾要素(ファイル名)を返す → access_log
dirname:パスのディレクトリ部分を返す → /var/log/httpd

どちらも GNU coreutils に含まれており、RHEL / Ubuntu / Debian / AlmaLinux などほぼ全てのLinuxディストリビューションで標準インストールされています。

basename コマンドの基本的な使い方

1. ファイル名を取り出す

最も基本的な使い方です。フルパスを引数として渡すと、ディレクトリ部分を除いたファイル名が返ります。

# フルパスからファイル名だけを取得 $ basename /var/log/httpd/access_log access_log # 末尾にスラッシュがあっても正常に動作する $ basename /var/log/httpd/ httpd # ファイル名だけのパスを渡すとそのまま返る $ basename access_log access_log

2. 拡張子を除いたファイル名を取得する

第2引数に拡張子を指定すると、拡張子を取り除いたファイル名が返ります。バックアップスクリプトや変換スクリプトでファイル名のベース部分だけが必要な場合に便利です。

# .log 拡張子を除いたファイル名を取得 $ basename /var/log/httpd/access_log .log access # .tar.gz の場合は1段ずつ除去する(2回実行が確実) $ basename /backup/server_2026-05-20.tar.gz .gz server_2026-05-20.tar $ basename server_2026-05-20.tar .tar server_2026-05-20

注意: .tar.gz のような複合拡張子は1回の basename では取り除けません。2段階で処理するか、後述の変数展開(${var%.*})を組み合わせる方法があります。

3. -a オプションで複数ファイルを一括処理(GNU版のみ)

GNU coreutils の basename-a オプションで複数のパスをまとめて処理できます。

# 複数パスを一括でファイル名取得(GNU bash版) $ basename -a /etc/hosts /etc/passwd /etc/group hosts passwd group

ただし、macOS (BSD版) では -a オプションは挙動が異なります。移植性が必要なスクリプトではループ処理を使うほうが安全です。

dirname コマンドの基本的な使い方

1. ディレクトリパスを取り出す

dirname はパスからディレクトリ部分を返します。

# フルパスからディレクトリ部分を取得 $ dirname /var/log/httpd/access_log /var/log/httpd # ファイル名だけを渡すと . (カレントディレクトリ) を返す $ dirname access_log . # 末尾スラッシュつきのディレクトリ $ dirname /var/log/httpd/ /var/log # ルートパスの場合 $ dirname /etc/hosts /etc

2. dirname の特殊なケース

ルートディレクトリやスラッシュのみを渡した場合の動作を把握しておきましょう。

# ルートを渡すとルートが返る $ dirname / / # 相対パスも正しく処理される $ dirname logs/access_log logs $ dirname ../config/settings.conf ../config

シェルスクリプトでの実践活用パターン

1. スクリプト自身のディレクトリを取得する

シェルスクリプト内で「このスクリプト自身が置かれているディレクトリ」を取得する定番パターンです。スクリプトをどこから実行しても正しいパスを参照できるため、設定ファイルや補助スクリプトの読み込みに非常によく使います。

#!/bin/bash # スクリプト自身のディレクトリを取得するイディオム SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) echo "スクリプトの場所: ${SCRIPT_DIR}" # 同じディレクトリの設定ファイルを読み込む source "${SCRIPT_DIR}/config.sh"

ポイント: dirname "$0" だけでは相対パスが返ることがあるため、cd && pwd を組み合わせて絶対パスを確定させるのが鉄板です。

2. for ループで拡張子変換(バッチ処理)

ディレクトリ内の複数ファイルを別の拡張子に変換するバッチスクリプトのパターンです。

#!/bin/bash # /backup/ 以下の .log ファイルを .txt にコピーする例 SRC_DIR="/var/log/httpd" DST_DIR="/backup/logs" for filepath in "${SRC_DIR}"/*.log; do # ファイル名(拡張子あり)を取得 filename=$(basename "${filepath}") # 拡張子を除いたベース名を取得 basename_no_ext=$(basename "${filepath}" .log) echo "処理中: ${filename} -> ${basename_no_ext}.txt" cp "${filepath}" "${DST_DIR}/${basename_no_ext}.txt" done

実際のサーバーで実行した場合の出力例です:

処理中: access_log -> access.txt 処理中: error_log -> error.txt 処理中: ssl_access_log -> ssl_access.txt

3. find と組み合わせてファイル名だけを使う

find で取得したフルパスからファイル名だけを使いたい場合の組み合わせです。

# find で .conf ファイルを探し、ファイル名のみを表示する $ find /etc -name "*.conf" -type f | while read -r filepath; do echo "$(basename "${filepath}")" done # 実行結果(例) httpd.conf ssl.conf resolv.conf nsswitch.conf

find -printf "%f\n" という方法もありますが、basename を使うほうが可読性が高く、後続処理と組み合わせやすいため実務では好まれます。find コマンドとの組み合わせは Linux 基本コマンドの解説 も参考にしてください。

4. バックアップスクリプトでの活用

バックアップ先のディレクトリを動的に作成し、元ファイルと同じ名前で保存するスクリプトの例です。

#!/bin/bash # 設定ファイルをタイムスタンプ付きでバックアップする TARGET_FILE="$1" # 例: /etc/nginx/nginx.conf if [[ -z "${TARGET_FILE}" ]]; then echo "使い方: $0 <バックアップするファイルパス>" exit 1 fi # ファイル名とディレクトリを取得 fname=$(basename "${TARGET_FILE}") fdir=$(dirname "${TARGET_FILE}") # バックアップ先ディレクトリを作成 BACKUP_DIR="/backup$(fdir)" mkdir -p "${BACKUP_DIR}" # タイムスタンプ付きでコピー TIMESTAMP=$(date +%Y%m%d_%H%M%S) cp "${TARGET_FILE}" "${BACKUP_DIR}/${fname}.${TIMESTAMP}.bak" echo "バックアップ完了: ${BACKUP_DIR}/${fname}.${TIMESTAMP}.bak"

実際に /etc/nginx/nginx.conf を引数に渡して実行した場合の出力です:

# ./backup.sh /etc/nginx/nginx.conf を実行した場合 バックアップ完了: /backup/etc/nginx/nginx.conf.20260520_142301.bak

このパターンは実務でも頻繁に使います。tar コマンドと組み合わせたアーカイブ作成については tar コマンドの実用例 もあわせて確認してください。

変数展開との使い分け

bash の変数展開機能(${var##*/}${var%/*})でも似た操作ができます。それぞれの使い分けを理解しておくと便利です。

やりたいこと コマンド・変数展開 特徴
ファイル名を取得 basename "$path" 可読性が高い。外部コマンド呼び出し
ファイル名を取得(変数展開) ${path##*/} サブシェル不要。高速だが可読性が低い
ディレクトリを取得 dirname "$path" 可読性が高い。外部コマンド呼び出し
ディレクトリを取得(変数展開) ${path%/*} サブシェル不要。高速だが可読性が低い
拡張子を除いたファイル名 basename "$path" ".${ext}" 拡張子が固定の場合に明確
拡張子を除いたファイル名(変数展開) ${filename%.*} 任意の拡張子に対応。サブシェル不要

判断基準: ループ内で何千回も呼び出す場合は変数展開(サブシェル不要で高速)、保守性を重視するスクリプトでは basename / dirname を使うのが現場の一般的な方針です。

応用・実務 Tips

1. シンボリックリンクに注意する

dirname "$0" でシンボリックリンクが絡む場合、リンク先ではなくリンク元のパスが返ることがあります。スクリプトの場所を確実に解決したい場合は readlink -f を使います。

#!/bin/bash # シンボリックリンクも解決した絶対パスでスクリプトディレクトリを取得 REAL_PATH=$(readlink -f "$0") SCRIPT_DIR=$(dirname "${REAL_PATH}") echo "スクリプトの実体パス: ${REAL_PATH}" echo "スクリプトのディレクトリ: ${SCRIPT_DIR}"

2. スペースや特殊文字を含むパスへの対処

パスにスペースや特殊文字が含まれる場合、必ずダブルクォートで囲みます。これはシェルスクリプトの基本中の基本ですが、basename / dirname でも例外ではありません。

# NG: クォートなし(スペース入りパスでエラー) path="/home/user/My Documents/report.txt" basename $path # 「Documents/report.txt」などで誤動作 # OK: ダブルクォートで囲む basename "$path" # report.txt dirname "$path" # /home/user/My Documents

3. ls と組み合わせてディレクトリ構成を整理する

ls コマンドで取得したパスリストから、ファイル名だけを整形表示する例です。ls コマンドのオプション一覧は ls コマンドの基本オプション を参照してください。

# /etc/cron.d/ のファイル名だけをリストアップ $ for f in /etc/cron.d/*; do echo "$(basename "$f")" done # 実行結果(例) 0hourly dailyjobs raid-check sysstat

よくあるエラーと対処法

「basename: missing operand」が出た時の対処

引数を渡さずに実行した場合に出るエラーです。変数が空になっていないか確認します。

# エラーが出る例(変数が空) $ MYPATH="" $ basename "$MYPATH" basename: missing operand Try 'basename --help' for more information. # 対策:スクリプト内で空チェックを行う if [[ -z "${MYPATH}" ]]; then echo "エラー: パスが指定されていません" exit 1 fi basename "$MYPATH"

相対パスを渡した場合の dirname の挙動

相対パスを dirname に渡すと、相対パスのディレクトリ部分が返ります。期待した絶対パスが返らない場合は realpath で先に絶対パスに変換してから処理します。

# 相対パスを渡すと相対ディレクトリが返る $ dirname logs/access_log logs # realpath で絶対パスに変換してから dirname に渡す $ dirname "$(realpath logs/access_log)" /var/log/httpd # realpath が使えない環境では readlink -f で代替 $ dirname "$(readlink -f logs/access_log)" /var/log/httpd

本記事のまとめ

やりたいこと コマンド
ファイル名を取り出す basename /path/to/file.txt
拡張子を除いたファイル名を取り出す basename /path/to/file.txt .txt
ディレクトリ部分を取り出す dirname /path/to/file.txt
スクリプト自身のディレクトリを取得する dirname "$0"(絶対パスは cd && pwd と組み合わせ)
シンボリックリンクを解決してディレクトリを取得する dirname "$(readlink -f "$0")"
複数ファイルのファイル名を一括取得(GNU版) basename -a /path1 /path2
変数展開でファイル名を取得(高速) ${path##*/}
変数展開でディレクトリを取得(高速) ${path%/*}
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。
Linux無料マニュアルを受け取る >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。