basename はパスから「最後の要素(ファイル名)」を、dirname は「最後の要素を除いた部分(親ディレクトリ)」を取り出すコマンドです。 どちらもパスを文字列として切り分けるだけで、ファイルが実在するかどうかは見ません。絶対パスに直したいときは realpath を組み合わせます。

この記事では、「パスから欲しい部分 → コマンド → パラメータ展開 → 出力」を1枚の早見表にまとめたうえで、.tar.gz、ドットで始まるファイル、拡張子なし、末尾スラッシュ、空白入りパスといった境界例を すべて実際に実行した結果で示します。basename -s と -a、realpath と readlink -f の違い、macOS(BSD 版)で使えないオプション、スクリプト自身の場所を取る定型句も載せました。

実行環境は Ubuntu 24.04 LTS、GNU coreutils 9.4(basename・dirname・realpath・readlink)、GNU bash 5.2.21 です。出力中のホームディレクトリは /home/taro/demo に置き換えています(表示は環境に合わせて置き換えています)。

basename・dirname の早見表

例のパスは p=/var/log/app/access.log です。出力はすべて実行して確かめたものです。

欲しい部分 コマンド パラメータ展開(bash / sh) 出力
ファイル名 basename "$p" "${p##*/}" access.log
拡張子なしのファイル名 basename "$p" .log または basename -s .log "$p" f="${p##*/}"; "${f%.*}" access
拡張子だけ (専用コマンドなし) f="${p##*/}"; "${f##*.}" log
親ディレクトリ dirname "$p" "${p%/*}" /var/log/app
2つ上のディレクトリ dirname "$(dirname "$p")" q="${p%/*}"; "${q%/*}" /var/log
絶対パス(リンクも解決) realpath "$p" (なし) /var/log/app/access.log
複数パスのファイル名 basename -a p1 p2 ループで "${x##*/}" 1行に1つずつ

パラメータ展開の読み方は次の4つだけ覚えれば足ります。

書き方 意味 覚え方
${p##*/} 先頭から、最後の / までを取り除く(最長一致) # は左側を削る。2つ重ねると最長
${p%/*} 末尾から、最後の / 以降を取り除く(最短一致) % は右側を削る。1つは最短
${f%.*} 末尾から、最後の . 以降を取り除く 拡張子を1つ外す
${f##*.} 先頭から、最後の . までを取り除く 拡張子だけ残す

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Linux basename・dirnameの使い方 ファイル名と拡張子取得」

basename でファイル名を取り出す

基本の形

basename /var/log/app/access.log
dirname  /var/log/app/access.log
access.log
/var/log/app

basename は最後のスラッシュより後ろ、dirname は最後のスラッシュより前を返します。どちらも文字列を切り分けるだけなので、存在しないパスを渡しても同じ結果になります。

拡張子を外す2つの書き方

basename /var/log/app/access.log .log      # 第2引数に接尾辞
basename -s .log /var/log/app/access.log   # -s オプションで接尾辞
access
access

結果は同じですが、-s は複数のパスをまとめて渡せるところが違います。第2引数の形は、パスを2つ並べると2つ目が「接尾辞」として解釈されます。

basename /a/one.txt /b/two.txt            # 2つ目は接尾辞あつかい
basename /a/one.txt /b/two.txt /c/3.txt   # 3つ目は受け取れない
basename -s .txt /a/one.txt /b/two.txt    # -s なら複数パスOK
one.txt
basename: extra operand '/c/3.txt'
Try 'basename --help' for more information.
one
two

1行目は「/a/one.txt から接尾辞 /b/two.txt を外す」と解釈され、外すものがないので one.txt がそのまま出ています。エラーにならないぶん気づきにくいので、複数のパスを渡すときは -a か -s を付けると覚えておくと安心です。

basename -a で複数パスをまとめて処理する

basename -a /a/one.txt /b/two.txt
basename -a -s .txt /a/one.txt /b/two.md
one.txt
two.txt
one
two.md

-a(--multiple)はすべての引数をパスとして扱います。-s は -a を兼ねるので、接尾辞を外したいときは -s だけで十分です。2つ目の例のとおり、接尾辞が一致しないファイル(two.md)はそのまま出力されます。

basename・dirname のオプション一覧

コマンド オプション 働き
basename -a / --multiple 引数をすべてパスとして処理する
basename -s 接尾辞 / --suffix=接尾辞 末尾の接尾辞を外す(-a を兼ねる)
basename -z / --zero 出力の区切りを改行ではなく NUL 文字にする
dirname -z / --zero 出力の区切りを NUL 文字にする
共通 -- これ以降をオプションではなくパスとして扱う

dirname は -a なしで複数のパスを受け取れます。

dirname /a/one.txt /b/c/two.txt
/a
/b/c

-z は、改行を含むファイル名でも安全に受け渡したいときに xargs -0 などと組み合わせて使います。

basename -z /a/one.txt | od -c | head -1
0000000   o   n   e   .   t   x   t  \0

境界例の実行結果をまとめて確認する

ここがこの記事の中心です。basename・dirname とパラメータ展開は、ふつうのパスでは同じ結果になりますが、境界例では結果が分かれます。 次の表は、1行ずつ実際に実行して得た結果です([] は空文字列)。

ファイル名と親ディレクトリ

入力パス basename dirname ${p##*/} ${p%/*}
/data/backup.tar.gz backup.tar.gz /data backup.tar.gz /data
/home/taro/.bashrc .bashrc /home/taro .bashrc /home/taro
/usr/bin/make make /usr/bin make /usr/bin
/data/my report.txt my report.txt /data my report.txt /data
/var/log/app/(末尾スラッシュ) app /var/log [] /var/log/app
/var/log/app// app /var/log [] /var/log/app/
/ / / [] []
access.log(スラッシュなし) access.log . access.log access.log
./a.txt a.txt . a.txt .
a/b b a b a
. . . . .
.. .. . .. ..
/access.log(ルート直下) access.log / access.log []
空文字列 [] . [] []

結果が分かれるのは次の4つの場面です。

場面 コマンドの結果 パラメータ展開の結果 対応
末尾にスラッシュがある 末尾のスラッシュを無視して切り分ける ファイル名が空になる 先に p="${p%/}" で末尾を1つ外す
スラッシュを含まない dirname は . を返す ${p%/*} は元の文字列のまま case "$p" in */*) ...;; *) d=.;; esac で分ける
ルート直下のファイル dirname は / を返す ${p%/*} は空になる 空なら / を補う
/ そのもの どちらも / どちらも空 コマンドを使う

末尾スラッシュを外してから切り出す例です。

p=/var/log/app/
echo "[${p##*/}]"
p2=${p%/}
echo "[${p2##*/}]"
[]
[app]

入力の形が読めないとき(利用者が入力したパス、末尾スラッシュつきのディレクトリなど)は basename・dirname、形が決まっているループの中ではパラメータ展開、と使い分けると迷いません。

拡張子の取り出し

ファイル名 f="${p##*/}" を取り出したあとの結果です。

ファイル名 f ${f%.*}(最後の拡張子を外す) ${f%%.*}(最初のドット以降を外す) ${f##*.}(最後の拡張子) ${f#*.}(最初のドットより後ろ)
report.txt report report txt txt
backup.tar.gz backup.tar backup gz tar.gz
archive.v1.2.tgz archive.v1.2 archive tgz v1.2.tgz
my report.txt my report my report txt txt
.bashrc [] [] bashrc bashrc
.config.yml .config [] yml config.yml
make(拡張子なし) make make make make

ここから3つのことが読み取れます。

  • .tar.gz をまとめて外したいときは %%.*、最後の1つだけ外したいときは %.* を使います。ただし archive.v1.2.tgz のように名前の途中にドットがあると %%.* は archive まで削るので、接尾辞がわかっているなら basename "$p" .tar.gz と明示するほうが確実です。
  • ドットで始まるファイル(.bashrc)は、${f%.*} が空になります。先頭のドットを拡張子の区切りとして扱ってしまうためです。
  • 拡張子がないファイル(make)は、${f##*.} がファイル名そのものを返します。「拡張子なし」を空文字列として受け取りたいときは、下の関数のように場合分けします。

.tar.gz を接尾辞で外す例です。

basename /data/backup.tar.gz .tar.gz
backup

もう1つ知っておくと役立つのが、パス全体に直接 ${p##*.} を当てると、ディレクトリ名のドットに反応することです。

p=/data.d/make
echo "${p##*.}"
d/make

先に ${p##*/} でファイル名にしてから拡張子を取り出す、という順番を守るとこの結果を避けられます。

拡張子を安全に取り出す関数(コピペ用)

ドットで始まるファイルと拡張子なしのファイルを、空文字列として返す関数です。

#!/usr/bin/env bash
# 拡張子を返す。拡張子がなければ空文字列を返す
ext() {
  local f="${1##*/}"          # まずファイル名だけにする
  case "$f" in
    .*.*) echo "${f##*.}" ;;  # .config.yml -> yml
    .*)   echo "" ;;          # .bashrc     -> (なし)
    *.*)  echo "${f##*.}" ;;  # report.txt  -> txt
    *)    echo "" ;;          # make        -> (なし)
  esac
}

for p in /data/report.txt /home/taro/.bashrc /usr/bin/make \
         /data/backup.tar.gz /data/.config.yml /data.d/make; do
  printf '%s -> [%s]\n' "$p" "$(ext "$p")"
done
/data/report.txt -> [txt]
/home/taro/.bashrc -> []
/usr/bin/make -> []
/data/backup.tar.gz -> [gz]
/data/.config.yml -> [yml]
/data.d/make -> []

接尾辞がファイル名全体と同じ場合

basename /data/.log .log
basename -s .log /data/.log
.log
.log

接尾辞がファイル名全体と一致するときは、basename は何も外しません。 空文字列になることを防ぐための仕様で、パラメータ展開の ${f%.*} が空を返すのと対照的です。

空白入りパスとエラーになる例

変数は必ずダブルクォートで囲む

p="/data/my report.txt"
basename $p      # クォートなし
basename "$p"    # クォートあり
dirname $p       # クォートなし
my
my report.txt
/data
.

クォートがないと、シェルが空白でパスを2つに分けてからコマンドに渡します。basename は「/data/my から接尾辞 report.txt を外す」と解釈して my を返し、dirname は2つのパスとして処理して2行を返します。どちらもエラーにならずに別の結果を返すので、"$p" と書く習慣が最も効きます。

よく出るエラー文と直し方

実行したコマンド 出力 終了ステータス 直し方
basename basename: missing operand 1 引数を渡す。変数が空でないか確認する
dirname dirname: missing operand 1 同上
basename a b c basename: extra operand 'c' 1 -a を付けるか、変数をクォートする
basename -n.txt basename: invalid option -- 'n' 1 basename -- -n.txt と書く
basename "" (空行) 0 空かどうかを先に確認する
dirname "" . 0 同上

ハイフンで始まるファイル名は、-- を挟むとパスとして扱われます。

basename -- -n.txt
-n.txt

missing operand は、クォートなしの変数が空だったときによく出ます。basename $p は p が空だと引数なしの basename になるためです。basename "$p" と書けば空行が返るだけで、エラーにはなりません。スクリプトでは basename -- "$p" の形を定型にしておくと、空白・空文字列・ハイフン始まりの3つをまとめて扱えます。

空の変数を早めに知らせたい場合は、次の1行を足します。

: "${p:?パスが空です}"

realpath で絶対パスを取り出す

basename・dirname は文字列を切るだけなので、../conf/app.conf のような相対パスやシンボリックリンクはそのまま残ります。実際の場所を知りたいときは realpath を使います。

検証用に次の構成を作りました。

/home/taro/demo/
├── real/sub/app.conf        ← 実体
├── link -> real             ← ディレクトリへのリンク
└── work/
    ├── conf.lnk -> ../real/sub/app.conf
    └── broken -> nowhere    ← リンク先が存在しない
realpath link/sub/app.conf
realpath real/sub/../sub/./app.conf
realpath work/conf.lnk
realpath -s work/conf.lnk
readlink work/conf.lnk
/home/taro/demo/real/sub/app.conf
/home/taro/demo/real/sub/app.conf
/home/taro/demo/real/sub/app.conf
/home/taro/demo/work/conf.lnk
../real/sub/app.conf
  • realpath は .. や . を畳み、シンボリックリンクをたどった絶対パスを返します。
  • -s(--no-symlinks)を付けると、リンクをたどらずに絶対パスへ直すだけになります。
  • オプションなしの readlink は、リンクに書かれている内容をそのまま表示します。

realpath と readlink -f の違い

どちらも絶対パスを返しますが、存在しないパスを渡したときのメッセージと、相対パスへの変換機能が違います。

確認したこと realpath readlink
既定の動作 絶対パスに直す リンクの中身を表示する
絶対パスに直す realpath p readlink -f p
最後の要素だけ存在しない パスを表示(終了 0) -f でパスを表示(終了 0)
途中のディレクトリが存在しない エラー文を表示(終了 1) -f は何も表示しない(終了 1)
すべて存在することを求める -e -e
存在しなくても計算する -m -m
リンクをたどらない -s (なし)
相対パスに直す --relative-to=DIR (なし)
リンクでないファイルを渡す 絶対パスを表示 オプションなしだと何も表示せず終了 1

実行結果です。

realpath work/none.txt              # 最後の要素だけ存在しない
realpath work/none/none.txt         # 途中のディレクトリも存在しない
readlink -f work/none/none.txt; echo "rc=$?"
realpath -e work/none.txt
realpath -m work/none/none.txt
realpath work/broken                # リンク先が存在しないリンク
/home/taro/demo/work/none.txt
realpath: work/none/none.txt: No such file or directory
rc=1
realpath: work/none.txt: No such file or directory
/home/taro/demo/work/none/none.txt
/home/taro/demo/work/nowhere

readlink -f は何も表示せずに終了ステータス 1 だけを返すので、原因を画面で確かめたいときは realpath のほうが読みやすいです。これから作るファイルのパスを計算したい場合は -m が向いています。

相対パスに直す

realpath --relative-to=work real/sub/app.conf
realpath --relative-base=/home/taro/demo/real real/sub/app.conf /etc/hosts
../real/sub/app.conf
sub/app.conf
/etc/hosts

--relative-to は「指定したディレクトリから見た相対パス」を返します。--relative-base は、指定したディレクトリの下にあるものだけ相対パスにして、外にあるものは絶対パスのまま返します。シンボリックリンクを相対パスで張るときに便利です。

pwd と pwd -P の違い

リンク経由で移動したディレクトリでは、pwd の表示と実体の場所が変わります。

cd link/sub
pwd
pwd -P
/home/taro/demo/link/sub
/home/taro/demo/real/sub

pwd は移動してきた経路、pwd -P はリンクを解決した実体の場所を表示します。あとで出てくる「スクリプト自身の場所」を取る定型句でも、この違いが効いてきます。

スクリプト自身の場所を取る定型句

設定ファイルや補助スクリプトを「スクリプトと同じディレクトリ」から読みたい場面は多くあります。カレントディレクトリに頼らず、スクリプトの場所を基準にするのが定石です。

#!/usr/bin/env bash
echo "\$0              = $0"
echo "BASH_SOURCE     = ${BASH_SOURCE[0]}"
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
echo "SCRIPT_DIR      = $SCRIPT_DIR"
REAL_DIR="$(dirname -- "$(realpath -- "${BASH_SOURCE[0]}")")"
echo "REAL_DIR        = $REAL_DIR"
echo "SCRIPT_NAME     = $(basename -- "${BASH_SOURCE[0]}")"

これを sd/bin/where.sh として保存し、sd/lnk/w というシンボリックリンクも作って、呼び出し方を変えて実行しました。

呼び出し方 $0 SCRIPT_DIR(cd と pwd) REAL_DIR(realpath)
./sd/bin/where.sh ./sd/bin/where.sh /home/taro/demo/sd/bin /home/taro/demo/sd/bin
cd sd && bin/where.sh bin/where.sh /home/taro/demo/sd/bin /home/taro/demo/sd/bin
bash sd/bin/where.sh sd/bin/where.sh /home/taro/demo/sd/bin /home/taro/demo/sd/bin
PATH 経由で where.sh /home/taro/demo/sd/bin/where.sh /home/taro/demo/sd/bin /home/taro/demo/sd/bin
source sd/bin/where.sh 呼び出し元の名前 /home/taro/demo/sd/bin /home/taro/demo/sd/bin
リンク経由 sd/lnk/w sd/lnk/w /home/taro/demo/sd/lnk /home/taro/demo/sd/bin

読み取れることは2つです。

  • source で読み込むと $0 は呼び出し元を指すので、${BASH_SOURCE[0]} を使うほうが広い場面で同じ結果になります。
  • シンボリックリンク経由で起動されると、cd と pwd の形はリンクが置かれたディレクトリを返します。実体の場所が欲しいときは realpath の形を使います。

用途別の選び方です。

目的 定型句
ふつうはこれ(bash) SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
リンク経由でも実体の場所が欲しい SCRIPT_DIR="$(dirname -- "$(realpath -- "${BASH_SOURCE[0]}")")"
sh(dash など)でも動かしたい SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
スクリプト名をメッセージに出す SCRIPT_NAME="$(basename -- "$0")"

使い方の例です。

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"

source "$SCRIPT_DIR/lib/common.sh"          # 同じ階層の lib を読む
CONF="$SCRIPT_DIR/../conf/app.conf"         # 1つ上の conf を指す
echo "使い方: $(basename -- "$0") 入力ファイル"

ループでの使い方とパラメータ展開の速さ

拡張子を付け替えて一括処理する

for f in lp/*; do
  n=$(basename -- "$f")
  echo "${n%.*}.bak"
done
a.bak
b c.bak
d.tar.bak

lp/ には a.txt、b c.txt、d.tar.gz を置いています。3つ目のとおり、%.* は最後の拡張子だけを外すので d.tar.bak になります。d.bak にしたい場合は basename -- "$f" .tar.gz のように接尾辞を明示します。

find と組み合わせる

find lp -type f -print0 | xargs -0 basename -a
find lp -type f -printf "%f\n" | sort
find lp -type f -printf "%h\n" | sort -u
d.tar.gz
b c.txt
a.txt
a.txt
b c.txt
d.tar.gz
lp

-print0 と xargs -0 の組み合わせで、空白入りのファイル名も1つのパスとして basename に渡せます。GNU find では -printf "%f\n" がファイル名、"%h\n" が親ディレクトリを直接出力するので、basename・dirname を呼ばずに済みます。

2,000回呼んだときの時間

time (for i in $(seq 2000); do basename /a/b/c.txt >/dev/null; done)
time (for i in $(seq 2000); do p=/a/b/c.txt; : "${p##*/}"; done)
real    0m2.947s   # basename を2,000回
real    0m0.007s   # パラメータ展開を2,000回

basename は外部コマンドなので、呼ぶたびにプロセスを起動します。この環境では2,000回で約2.9秒、パラメータ展開は約0.007秒でした。数十回なら差は気になりませんが、数千件を回すループではパラメータ展開が向いています。 時間は環境によって変わるので、目安として読んでください。

どちらを使うかの判断表

状況 おすすめ 理由
対話的に1回だけ確かめたい basename / dirname 読みやすく、境界例の扱いが安定している
入力の形が読めない(末尾スラッシュ、スラッシュなし) basename / dirname 早見表の4つの場面でも期待どおりに切り分ける
件数の多いループ パラメータ展開 プロセスを起動しないので速い
拡張子だけ欲しい パラメータ展開 basename には拡張子だけを返す機能がない
複数パスをまとめて処理 basename -a / -s 1回の起動で済む
sh(dash)で動かす どちらも可 ##・% は POSIX sh でも使える

最後の行は /bin/sh が dash の環境で確かめました。

sh -c 'p=/var/log/a.txt; echo "${p##*/} ${p%/*}"'
a.txt /var/log

macOS(BSD 版)で使えないオプション

macOS に入っている basename・dirname・realpath・readlink は BSD 系の実装で、GNU coreutils とはオプションが一部異なります。この節は macOS の実機がなく未実行です。一般に知られた仕様として整理しているので、手元の man basename などで確かめてから使ってください。

やりたいこと Linux(GNU) macOS(BSD)での扱い(未実行) 両方で動く書き方
接尾辞を外す basename -s .log p -s は使える basename p .log
複数パス basename -a p1 p2 -a は使える ループで1つずつ
長いオプション --suffix=.log、--multiple 使えない 短いオプションを使う
NUL 区切り basename -z / dirname -z 使えない "${p##*/}" をループで
絶対パス realpath p 新しい macOS には realpath があるが、-m・-e・-s・--relative-to は使えない cd と pwd -P の組み合わせ
リンクを解決 readlink -f p 新しい macOS では -f が使えるが、以前の版では使えない 同上
find でファイル名 find -printf "%f\n" -printf が使えない find ... -exec basename {} \;

macOS と Linux の両方で動かすスクリプトでは、次の形が扱いやすいです。

# ディレクトリの実体の絶対パス(GNU / BSD 共通)
abs_dir="$(cd -- "$(dirname -- "$p")" && pwd -P)"
abs_path="$abs_dir/$(basename -- "$p")"

GNU 版と同じオプションを macOS で使いたい場合は、Homebrew の coreutils を入れると gbasename、grealpath、greadlink のように先頭に g が付いた名前で使えます(未実行)。

目的別の逆引き表

やりたいこと 書き方
ファイル名を取り出す basename -- "$p"
拡張子なしのファイル名 basename -- "$p" .txt
.tar.gz をまとめて外す basename -- "$p" .tar.gz
拡張子を付け替える f="${p##*/}"; new="${f%.*}.bak"
同じディレクトリに別名で出力する out="$(dirname -- "$p")/$(basename -- "$p" .csv).json"
親ディレクトリの名前だけ basename -- "$(dirname -- "$p")"
2つ上のディレクトリ dirname -- "$(dirname -- "$p")"
絶対パスに直す realpath -- "$p"
まだ存在しないパスを絶対パスに realpath -m -- "$p"
リンクをたどらず絶対パスに realpath -s -- "$p"
リンクの中身を見る readlink -- "$p"
ある場所から見た相対パス realpath --relative-to="$base" -- "$p"
スクリプトのあるディレクトリ cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd
複数ファイルの名前を一覧 basename -a -- "$@"

「同じディレクトリに別名で出力する」を動かすとこうなります。

p="/data/in/sales 2026.csv"
out="$(dirname -- "$p")/$(basename -- "$p" .csv).json"
echo "$out"
/data/in/sales 2026.json

書く前のチェックリスト

確認すること 見るポイント
変数をダブルクォートで囲んだか basename "$p"。空白入りパスが2つに分かれない
-- を入れたか ハイフンで始まるファイル名をパスとして扱える
複数パスに -a か -s を付けたか 2つ目が接尾辞あつかいにならない
末尾スラッシュの可能性があるか パラメータ展開なら先に ${p%/}
拡張子なし・ドット始まりを考えたか ${f##*.} はファイル名そのものを返す
パス全体に ##*. を当てていないか ディレクトリ名のドットに反応する
絶対パスが必要か basename・dirname は相対パスのまま。realpath を使う
macOS でも動かすか 短いオプションと pwd -P の形にそろえる

よくある質問

Q. basename で拡張子だけを取り出せますか? A. basename には拡張子だけを返す機能がありません。f="${p##*/}" でファイル名にしたあと "${f##*.}" で取り出します。拡張子がないファイルではファイル名そのものが返るので、空文字列で受け取りたい場合は本文の ext 関数のように場合分けしてください。

Q. dirname に相対パスやファイル名だけを渡すとどうなりますか? A. スラッシュを含まない access.log を渡すと .(カレントディレクトリ)が返ります。相対パスは相対パスのまま切り分けるので、絶対パスが必要なら realpath で直してから dirname に渡します。

Q. realpath と readlink -f はどちらを使えばよいですか? A. 絶対パスに直す目的ならどちらも同じ結果になります。途中のディレクトリが存在しないときに realpath はエラー文を表示し、readlink -f は何も表示せず終了ステータス 1 を返します。相対パスへの変換(--relative-to)やリンクをたどらない指定(-s)は realpath だけにあります。

Q. basename "$p" .log と basename -s .log "$p" は何が違いますか? A. 1つのパスなら結果は同じです。-s は複数のパスをまとめて渡せるところが違います。第2引数の形でパスを2つ並べると、2つ目が接尾辞として解釈されます。

まとめ

  • basename は最後のスラッシュより後ろ、dirname は前を返す。どちらも文字列を切るだけで、ファイルの存在は見ない
  • パラメータ展開は ${p##*/}(ファイル名)、${p%/*}(親)、${f%.*}(拡張子なし)、${f##*.}(拡張子) の4つで足りる
  • 末尾スラッシュ・スラッシュなし・ルート直下・/ の4つの場面でコマンドとパラメータ展開の結果が分かれる
  • .tar.gz は basename "$p" .tar.gz と接尾辞を明示すると確実。ドット始まりと拡張子なしは場合分けする
  • 複数パスは -a か -s、変数は basename -- "$p" の形を定型にする
  • 絶対パスは realpath。存在しないパスは -m、相対パスは --relative-to
  • スクリプトの場所は cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd。リンク経由でも実体が欲しければ realpath を使う

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Linux basename・dirnameの使い方 ファイル名と拡張子取得」

株式会社RJCでは、Linuxコマンドやシェルスクリプトの書き方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?