Bashスクリプトで現在のディレクトリ名(フルパスなし)を取得する


回答:


1116

basenameの必要はなく、特にpwdを実行するサブシェルは不要です(これにより、余分で高価なfork操作追加されます)。シェルはこれをパラメーター拡張を使用して内部的に実行できます。

result=${PWD##*/}          # to assign to a variable

printf '%s\n' "${PWD##*/}" # to print to stdout
                           # ...more robust than echo for unusual names
                           #    (consider a directory named -e or -n)

printf '%q\n' "${PWD##*/}" # to print to stdout, quoted for use as shell input
                           # ...useful to make hidden characters readable.

このテクニックを他の状況で適用している場合(ではなくPWD、ディレクトリ名を保持している他の変数)、末尾のスラッシュを削除する必要がある場合があることに注意してください。以下は、bashのextglobサポートを使用して、複数の末尾のスラッシュでも機能します。

dirname=/path/to/somewhere//
shopt -s extglob           # enable +(...) glob syntax
result=${dirname%%+(/)}    # trim however many trailing slashes exist
result=${result##*/}       # remove everything before the last / that still remains
printf '%s\n' "$result"

または、なしextglob

dirname="/path/to/somewhere//"
result="${dirname%"${dirname##*[!/]}"}" # extglob-free multi-trailing-/ trim
result="${result##*/}"                  # remove everything before the last /

31
$ {PWD ## * /}と$ PWDの違いは何ですか?
Mr_Chimp

24
@Mr_Chimp前者は、ベース名のみを提供するためにディレクトリの残りの部分をトリミングするパラメーター拡張操作です。パラメータ展開に関するドキュメントへの回答にリンクがあります。ご不明な点がございましたら、お気軽にご確認ください。
Charles Duffy

24
@stefgosselin $PWDは、組み込みのbash変数の名前です。すべての組み込み変数名は、すべて大文字です(ローカル変数と区別するために、常に少なくとも1つの小文字が必要です)。result=${PWD#*/}は評価されませ/full/path/to/directory。代わりに、最初の要素のみを取り除いて作成しpath/to/directoryます。2つの#文字を使用すると、パターンは貪欲に一致し、できるだけ多くの文字に一致します。詳細については、回答にリンクされているパラメーター展開ページをご覧ください。
Charles Duffy

5
からの出力pwdは、の値と常に同じであるとは限らないことに注意してください。これは、シンボリックリンクを介すること、bashにオプションが設定されているかどうか$PWDなどによって複雑になるためです。これは、自動マウントされたディレクトリの処理に関して特に厄介なものでした。論理パスではなく物理パスを記録すると、パスが生成され、オートマウンタが使用しているディレクトリを自発的にマウント解除できるようになります。cd-o physical
Alex North-Keys

3
いいね!誰かが私のような古いボーンシェルの人のために本を書くべきです。多分そこにあるのでしょうか?昔のsys管理者は、「私の時代に戻るだけshcsh、バックスペースキーを機能させるには、sttymanページ全体を読む必要があり、気に入った」と言っていたかもしれません。
レッドクリケット

335

basenameプログラムを使用します。あなたの場合:

% basename "$PWD"
bin

20
これはbasenameプログラムの目的ではありませんか?引用符がないこと以外に、この答えの何が問題になっていますか?
ナハト-モニカ

11
@Nachtはbasename確かに正しいことをする外部プログラムですが、実行中の任意のもののbashのために外部プログラムは、アウト・オブ・ボックス行うことができる唯一の組み込み機能が愚かで使用して、(パフォーマンスへの影響を被るfork()execve()wait()のために、など)理由はありません。
Charles Duffy 2013年

3
...余談として、私に異議basenameここにはいないに適用されますdirnameので、dirname機能がある${PWD##*/}のスラッシュなしで文字列を変換する-しない.例えばを、。したがって、dirname外部ツールとして使用するとパフォーマンスのオーバーヘッドが発生しますが、それを補うのに役立つ機能もあります。
Charles Duffy

4
@LouisMaddox、ちょっとした変更:functionキーワードはPOSIXと互換性がなく、標準化された構文に値を追加せず、引用符がないと、スペースを含むディレクトリ名にバグが発生します。wdexec() { "./$(basename "$PWD")"; }望ましい代替手段かもしれません。
Charles Duffy、2016年

28
確かに使用basenameは「効率的」ではありません。しかし、醜いbash構文に比べて覚えやすいので、開発者の生産性の点でおそらくより効率的です。覚えているなら、頑張ってね。それ以外の場合basenameも同様に機能します。誰かがbashスクリプトの「パフォーマンス」を改善してより効率的にしなければならなかったことがありますか?
usr

139
$ echo "${PWD##*/}"

​​​​​


2
@jocap ...ただし、引数を引用せずにechoを使用するのは間違っています。ディレクトリ名に複数のスペースまたはタブ文字がある場合は、1つのスペースに折りたたまれます。ワイルドカード文字がある場合は展開されます。正しい使い方はでしょうecho "${PWD##*/}"
Charles Duffy

9
@jocap ...また、「エコー」が実際に答えの正当な部分であるかどうかはわかりません 問題は、答えをどのように得るかであり、答えを印刷する方法ではありませんでした。たとえば、それを変数に割り当てることが目標である場合、それname=${PWD##*/}は正しく、name=$(echo "${PWD##*/}")間違っています(不必要な非効率的な意味で)。
Charles Duffy 2013年

24

pwdとbasenameの組み合わせを使用できます。例えば

#!/bin/bash

CURRENT=`pwd`
BASENAME=`basename "$CURRENT"`

echo "$BASENAME"

exit;

18
いいえ、いいえ。バッククォートはサブシェル(つまり、フォーク操作)を作成します-この場合、それらを2回使用しています![補足として、文体的な奇妙なことですが、変数名は、環境にエクスポートする場合や、特別な予約済みの場合を除いて、小文字にする必要があります]。
チャールズダフィー

11
また、2番目のスタイルとして、quibble backticsは$()で置き換える必要があります。まだフォークですが、より読みやすく、必要な制限が少なくなっています。
ジェレミーウォール

1
慣例により、環境変数(PATH、EDITOR、SHELLなど)および内部シェル変数(BASH_VERSION、RANDOMなど)は完全に大文字になります。他のすべての変数名は小文字でなければなりません。変数名では大文字と小文字が区別されるため、この規則により、環境変数と内部変数が誤って上書きされることが回避されます。
Rany Albeg Wein

2
規約に依存します。すべてのシェル変数は環境変数(シェルによって異なる)であるため、すべてのシェル変数はすべて大文字にする必要があると主張できます。他の誰かがスコープに基づいて議論することができます-グローバル変数はすべて大文字ですが、ローカル変数は小文字で、これらはすべてグローバルです。さらに別の人は、変数をすべて大文字にすることで、シェルスクリプトをポイ捨てするコマンドとのコントラストがさらに増すと主張するかもしれません。私はそれらの引数のいずれかに/同意/しないかもしれませんが、3つすべてが使用されているのを見てきました。:)
dannysauer 2017年

17

grepはどうですか:

pwd | grep -o '[^/]*$'

色情報は得られるようですが、得られpwd | xargs basenameないようです。おそらくそれほど重要ではありませんが、他の答えは環境全体でよりシンプルで一貫しています
davidhq

8

私は選択した回答(Charles Duffy)が好きですが、シンボリックリンクされたディレクトリにいて、ターゲットディレクトリの名前が必要な場合は注意してください。残念ながら、それは単一のパラメーター展開式では実行できないと思います。おそらく私は間違っています。これはうまくいくはずです:

target_PWD=$(readlink -f .)
echo ${target_PWD##*/}

これを見るには、実験:

cd foo
ln -s . bar
echo ${PWD##*/}

「バー」を報告する

DIRNAME

パスの先頭ディレクトリを表示するには(/ usr / bin / dirnameのfork-execを発生させずに):

echo ${target_PWD%/*}

これは、例えばfoo / bar / baz-> foo / barを変換します


5
残念ながら、これreadlink -fはGNU拡張機能であるため、BSD(OS Xを含む)では使用できません。
Xiong Chiamiov 2013年

8
echo "$PWD" | sed 's!.*/!!'

Bourneシェルを使用している場合、または${PWD##*/}使用できない場合。


4
参考までに、${PWD##*/}POSIX sh-すべての最新の/ bin / sh(ダッシュ、アッシュなどを含む)がサポートしています。最近のボックスで実際のボーンをヒットするには、少し古いSolarisシステムを使用する必要があります。それを超えて- echo "$PWD"; 引用符を省略するとバグが発生します(ディレクトリ名にスペース、ワイルドカード文字などが含まれている場合)。
Charles Duffy

1
はい、古いSolarisシステムを使用していました。引用符を使用するようにコマンドを更新しました。
異常な14

7

このスレッドは素晴らしいです!ここにもう1つのフレーバーがあります。

pwd | awk -F / '{print $NF}'

5

驚いたことに、組み込みのbashコマンドのみを使用するこの代替案については誰も言及していません。

i="$IFS";IFS='/';set -f;p=($PWD);set +f;IFS="$i";echo "${p[-1]}"

追加ボーナスとして、親ディレクトリの名前を簡単に取得できます。

[ "${#p[@]}" -gt 1 ] && echo "${p[-2]}"

これらはBash 4.3-alpha以降で動作します。


意外と?冗談ですが、他のものははるかに短く覚えやすい
codewandler

これはかなりおもしろいです= Pこの前に$ IFS(内部フィールド区切り文字)を聞いていませんでした。私のbashは古すぎましたが、ここでテストできます:jdoodle.com/test-bash-shell-script-online
Stan Kurdziel 2017

5

使用する:

basename "$PWD"

または

IFS=/ 
var=($PWD)
echo ${var[-1]} 

内部ファイル名区切り(IFS)をスペースに戻します。

IFS= 

IFSの後にスペースが1つあります。


4
basename $(pwd)

または

echo "$(basename $(pwd))"

2
正確にするためには、さらに引用符が必要です。つまり、の出力は、pwdに渡される前に文字列分割され、グロブ展開されbasenameます。
Charles Duffy

したがって、basename "$(pwd)"- basename "$PWD"それはjust に比べて非常に非効率的ですが、それ自体は、呼び出しbasenameを行う代わりにパラメーター展開を使用することに比べて非効率的です。
Charles Duffy

4

私のようなそこにいるジョッキーを見つけるために:

find $PWD -maxdepth 0 -printf "%f\n"

変更$PWD"$PWD"正しく珍しいディレクトリ名を処理するために。
Charles Duffy

3

私は通常、これをshスクリプトで使用します

SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
echo "Running from ${RUN_PATH}"
...
cd ${RUN_PATH}/subfolder

これを使用して物事を自動化できます...


readlink: illegal option -- f usage: readlink [-n] [file ...]


1

ただ使用する:

pwd | xargs basename

または

basename "`pwd`"

2
これは、すべての点で、以前にアルカディ(stackoverflow.com/a/1371267/14122)によって提供された回答のより悪いバージョンです:xargsディレクトリ名にリテラルの改行または引用文字が含まれ、2番目の公式がpwdコマンドを呼び出す場合、formultionは非効率的でバグが多いです組み込みの変数展開を介して同じ結果を取得するのではなく、サブシェルで。
チャールズダフィー2015年

@CharlesDuffyそれにもかかわらず、それは質問に対する有効で実用的な答えです。
バッフ

1

bashプロンプト領域の現在のディレクトリのみを表示したい場合は、で.bashrcファイルを編集できます~。次の行に変更\w\Wます。

PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

実行するsource ~/.bashrcと、プロンプト領域にディレクトリ名のみが表示されます。

参照:https : //superuser.com/questions/60555/show-only-current-directory-name-not-full-path-on-bash-prompt


0

/で終わるプレフィックスとサフィックス(文字列に存在する場合)を文字列から削除し、結果を標準出力に出力するbasenameユーティリティを使用できます。

$basename <path-of-directory>

0

gbasenameは、GNU coreutilsの一部であるを使用することを強くお勧めします。


ちなみに、Ubuntuディストリビューションには付属していません。
Katastic Voyage 2017

@KatasticVoyage、それはUbuntuにあり、そこに呼び出されbasenameているだけです。これは通常gbasename、MacOSや、GNU以外のベース名で出荷される他のプラットフォームでのみ呼び出されます。
Charles Duffy

-1

次のコマンドを実行すると、現在の作業ディレクトリがbashスクリプトで出力されます。

pushd .
CURRENT_DIR="`cd $1; pwd`"
popd
echo $CURRENT_DIR

2
(1)引数リストが$1現在の作業ディレクトリを含むようなものであることをどこで確認しているのかわかりません。(2)pushdおよびはpopdここでは何の目的も果たしません。これは、バッククォート内のすべてがサブシェルで行われるためです。つまり、最初は親シェルのディレクトリに影響を与えることはできません。(3)を使用"$(cd "$1"; pwd)"すると、空白を含むディレクトリ名に対してより読みやすく、復元力があります。
Charles Duffy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.