Bash betiğinde geçerli dizin adını (tam yol olmadan) alın


Yanıtlar:


1115

Basename gerekmiyor ve özellikle de bir subshell çalışan pwd'ye gerek yok ( ekstra ve pahalı bir çatal operasyonu ekliyor ); kabuk bunu parametre genişletme kullanarak dahili olarak yapabilir :

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.

Bu tekniği başka durumlarda uyguluyorsanız ( PWDdizin adını taşıyan başka bir değişken değil , bazı değişkenler), sondaki eğik çizgileri kırpmanız gerekebileceğini unutmayın. Aşağıdakiler, birden fazla sondaki eğik çizgi ile bile çalışmak için bash'ın extglob desteğini kullanır :

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"

Alternatif olarak extglob:

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

31
$ {PWD ## * /} ve $ PWD arasındaki fark nedir?
Mr_Chimp

24
@Mr_Chimp birincisi sadece taban adını sağlamak için dizinin geri kalanını kesen bir parametre genişletme işlemidir. Parametre genişletme ile ilgili belgelere cevabımda bir bağlantı var; Herhangi bir sorunuz varsa bunu takip etmekten çekinmeyin.
Charles Duffy

24
@stefgosselin $PWDyerleşik bir bash değişkeninin adıdır; tüm yerleşik değişken adları tamamen büyük harflidir (bunları her zaman en az bir küçük harf içermesi gereken yerel değişkenlerden ayırmak için). result=${PWD#*/}does not etmek değerlendirmek /full/path/to/directory; bunun yerine, yalnızca ilk öğeyi çıkarır path/to/directory; iki #karakter kullanmak , deseni olabildiğince çok karakterle eşleştirerek açgözlü eşleşmeyi sağlar. Daha fazla bilgi için cevaba bağlı parametre genişletme sayfasını okuyun.
Charles Duffy

5
Sembolik bağlantılardan kaynaklanan komplikasyonlar nedeniyle, bash seçeneğinin ayarlanıp ayarlanmadığından vb. Gelen çıktıların pwdher zaman değeriyle aynı olmadığını unutmayın . Bu, özellikle mantıksal yerine fiziksel yolun kaydedilmesinin, eğer kullanıldığında, otomatik sayacın kullanmakta olduğu dizini kendiliğinden çıkarmasına izin verecek bir yol üreteceği otomatik numaralandırılmış dizinlerin işlenmesi konusunda kötü olur. $PWDcd-o physical
Alex North-Keys

3
Güzel! Birisi benim gibi yaşlı Borne kabuğu adamları için bir kitap yazmalı. Belki orada bir tane var? O "biz sadece Benim zamanımda, eski sys gibi şeyler söyleyerek Yönetici bir crotchity olabilir shve cshsiz bütün okumuştuk çalışmak için geri tuşunu istiyorsa ve sttyadam sayfası ve biz sevdim!"
Red Cricket

335

basenameProgramı kullanın . Davanız için:

% basename "$PWD"
bin

20
Bu basenameprogramın amacı değil mi? Alıntıları kaçırmanın yanı sıra bu cevapta yanlış olan ne?
Nacht - Monica'yı

11
@Nacht basenamegerçekten doğru şeyi yapmıyor harici bir program olmakla birlikte, çalışan herhangi bir şey partisi yüzünden harici program dışı-box yapabileceği tek yerleşik işlevlerini saçma kullanılarak, (performans etkisini ödemeden fork(), execve(), wait()için, vs) sebep yok.
Charles Duffy

3
... bir yana, basenameburadaki itirazlarım geçerli değildirname , çünkü dirnameişlevsel ${PWD##*/}olmayan - eğik çizgi olmayan bir dizeyi dönüştürmek .. Bu nedenle, dirnameharici bir araç olarak kullanılırken performans yükü vardır, aynı zamanda bunu telafi etmeye yardımcı olan işlevselliğe de sahiptir.
Charles Duffy

4
@LouisMaddox, biraz kibitzing: functionAnahtar kelime, standart sözdizimine herhangi bir değer katmadan POSIX ile uyumsuzdur ve tırnak işaretleri boşluk içeren dizin adlarında hatalar oluşturur. wdexec() { "./$(basename "$PWD")"; }tercih edilebilir bir alternatif olabilir.
Charles Duffy

28
Emin basenamekullanım daha az "verimli". Ancak , geliştirici verimliliği açısından muhtemelen daha verimlidir, çünkü çirkin bash sözdizimine kıyasla hatırlanması kolaydır. Eğer hatırlarsanız, devam edin. Aksi takdirde, aynı şekilde basenameçalışır. Herkes bir bash betiğinin "performansını" geliştirmek ve daha verimli hale getirmek zorunda mıydı?
usr

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

​​​​​


2
@jocap ... argümanı söylemeden yankı kullanımının yanlış olması dışında . Dizin adında birden çok boşluk veya bir sekme karakteri varsa, tek bir boşluğa daraltılır; bir joker karakter varsa, genişletilir. Doğru kullanım olurdu echo "${PWD##*/}".
Charles Duffy

9
@jocap ... ayrıca, "yankı" nın aslında cevabın meşru bir parçası olduğundan emin değilim. Soru nasıl oldu almak nasıl cevap değil yazdırmak cevabı; eğer amaç onu bir değişkene atamak name=${PWD##*/}olsaydı, doğru name=$(echo "${PWD##*/}")olur ve yanlış olur (gereksiz verimsiz anlamda).
Charles Duffy

24

Pwd ve basename kombinasyonunu kullanabilirsiniz. Örneğin

#!/bin/bash

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

echo "$BASENAME"

exit;

18
Lütfen hayır. Backticks bir alt kabuk yaratır (böylece bir çatal işlemi) - ve bu durumda, bunları iki kez kullanıyorsunuz ! [Ek olarak, stilistik kelime oyunu olsa da - değişken adları çevreye dışa aktarmazsanız veya özel, ayrılmış bir durum olmadıkça küçük harf olmalıdır].
Charles Duffy

11
ve ikinci bir stil olarak, kelime oyunu backtics $ () ile değiştirilmelidir. hala çatal ama daha okunabilir ve daha az excaping ile.
Jeremy Wall

1
Geleneksel olarak, ortam değişkenleri (PATH, EDITOR, SHELL, ...) ve iç kabuk değişkenleri (BASH_VERSION, RANDOM, ...) tamamen büyük harfle yazılır. Diğer tüm değişken adları küçük harf olmalıdır. Değişken isimleri büyük / küçük harfe duyarlı olduğundan, bu sözleşme çevresel ve dahili değişkenleri yanlışlıkla geçersiz kılmayı önler.
Rany Albeg Wein

2
Sözleşmeye bağlıdır. Tüm kabuk değişkenlerinin ortam değişkenleri (kabuğa bağlı olarak) olduğu ve bu nedenle tüm kabuk değişkenlerinin tamamen büyük harflerde olması gerektiği söylenebilir. Birisi kapsamı temel alarak tartışabilir - küresel değişkenler büyük harf, yerel değişkenler küçük harftir ve bunların tümü küreseldir. Yine bir diğeri, değişkenleri büyük harf yapmanın, aynı zamanda küçük harfli kısa ama anlamlı kelimeler olan kabuk komut dosyalarını çöpleyen komutlarla ekstra bir kontrast katmanı eklediğini iddia edebilir. Bu argümanlardan herhangi birini kabul edebilirim / kabul etmeyebilirim / kabul edemeyebilirim, ancak üçünün de kullanımda olduğunu gördüm. :)
dannysauer

17

Grep hakkında nasıl:

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

tavsiye etmem çünkü bazı renk bilgileri alıyor gibi görünse de, pwd | xargs basenamemuhtemelen önemli değil ama diğer cevap daha basit ve ortamlar arasında daha tutarlı
davidhq

8

Seçilen cevabı seviyorum (Charles Duffy), ancak işaretlenmiş bir direkte iseniz ve hedef dir ismini istiyorsanız dikkatli olun. Ne yazık ki tek bir parametre genişletme ifadesinde yapılabileceğini sanmıyorum, belki yanılıyorum. Bu çalışmalı:

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

Bunu görmek için bir deneme:

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

raporlar "çubuk"

dizinadı

Bir yolun önde gelen dizinlerini göstermek için (/ usr / bin / dirname öğesinin fork-exec işlemine gerek kalmadan):

echo ${target_PWD%/*}

Bu, örneğin foo / bar / baz -> foo / bar'ı dönüştürür


5
Ne yazık ki, readlink -fbir GNU uzantısıdır ve bu nedenle BSD'lerde (OS X dahil) mevcut değildir.
Xiong Chiamiov

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

Bourne kabuğu kullanıyorsanız veya ${PWD##*/}kullanılamıyorsa.


4
FYI, ${PWD##*/}POSIX sh - her modern / bin / sh (çizgi, kül vb. Dahil) bunu destekler; yeni bir kutuda gerçek Bourne vurmak için, hafif eski bir Solaris sisteminde olmanız gerekir. Bunun ötesinde - echo "$PWD"; tırnak işaretlerini bırakmak hatalara yol açar (dizin adında boşluklar, joker karakterler vb. varsa).
Charles Duffy

1
Evet, eski bir Solaris sistemi kullanıyordum. Tırnakları kullanma komutunu güncelledim.
anomal

7

Bu konu harika! İşte bir lezzet daha:

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

5

Şaşırtıcı bir şekilde, hiç kimse sadece yerleşik bash komutlarını kullanan bu alternatiften bahsetmedi:

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

Ek bir bonus olarak, ana dizinin adını aşağıdakilerle kolayca elde edebilirsiniz:

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

Bunlar Bash 4.3-alfa veya daha yenisi üzerinde çalışır.


şaşırtıcı bir şekilde? sadece şaka, ama diğerleri çok daha kısa ve hatırlaması daha kolay
codewandler

Bu oldukça komik = P Bundan önce $ IFS (iç alan ayırıcı) duymamıştı. benim bash çok eski, ama burada test edebilirsiniz: jdoodle.com/test-bash-shell-script-online
Stan Kurdziel

5

kullanın:

basename "$PWD"

VEYA

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

Dahili Dosya Adı Ayırıcısını (IFS) tekrar boşluğa çevirin.

IFS= 

IFS'den sonra bir boşluk var.


4
basename $(pwd)

veya

echo "$(basename $(pwd))"

2
Doğru olması için daha fazla alıntı yapılması gerekiyor - olduğu gibi, çıktısı pwdaktarılmadan önce dize bölünmüş ve glob genişletilmiş basename.
Charles Duffy

Böylece, basename "$(pwd)"- bu sadece göre çok verimsiz olsa basename "$PWD", hangi kendisi bir parametre açılımı kullanılarak yerine çağırarak kıyasla verimsiz basenamehiç.
Charles Duffy

4

Orada benim gibi jokeyleri bulmak için:

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

Alışılmadık dizin adlarını doğru işlemek $PWDiçin "$PWD"olarak değiştirin .
Charles Duffy

3

bunu genellikle sh betiklerinde kullanırım

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

bunu otomatikleştirmek için kullanabilirsiniz ...


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

2

Regex ile grep'in altında da çalışıyor,

>pwd | grep -o "\w*-*$"

3
Dizin adı "-" karakterleri içeriyorsa çalışmaz.
daniula

1

Sadece kullan:

pwd | xargs basename

veya

basename "`pwd`"

2
Bu, her bakımdan Arkady tarafından verilen cevabın daha kötü bir versiyonudur ( stackoverflow.com/a/1371267/14122 ): xargsDizin adları değişmez yeni satırlar veya alıntı karakterler içerdiğinde ve ikinci formülasyon pwdkomutu çağırdığında formül yetersiz ve buggy yerleşik bir değişken genişletme yoluyla aynı sonucu almak yerine, bir alt kabukta.
Charles Duffy

@CharlesDuffy Yine de bu sorunun geçerli ve pratik bir cevabıdır.
bachph


0

Dize / ile biten önekleri ve dizede varsa (dize varsa) sonekleri silen ve sonucu standart çıktıya basan basename yardımcı programını kullanabilirsiniz.

$basename <path-of-directory>

0

gbasenameGNU coreutils'in bir parçası olan kullanmayı tercih ederim .


FYI, benim Ubuntu dağıtımımla gelmiyor.
Katastic Voyage

@KatasticVoyage, Ubuntu'da, sadece basenameorada deniyor . Yalnızca gbasenameMacOS ve diğer platformlarda denir , aksi takdirde GNU olmayan bir temel adla birlikte gönderilir.
Charles Duffy

-1

Aşağıdaki komutlar, geçerli çalışma dizininizi bash komut dosyasında yazdırmanıza neden olur.

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

2
(1) Bağımsız değişken listesinin $1geçerli çalışma dizinini içerecek şekilde olmasını sağladığımızdan emin değilim . (2) pushdve popdburada hiçbir amaca hizmet etmez, çünkü backticks içindeki herhangi bir şey bir alt kabukta yapılır - bu nedenle başlangıçta üst kabuğun dizinini etkileyemez. (3) "$(cd "$1"; pwd)"Boşluklu dizin adlarına karşı kullanmak hem daha okunabilir hem de daha dayanıklı olur.
Charles Duffy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.