Geçerli çalışma dizini komut dosyasının dizinine nasıl ayarlanır?


569

Bir bash senaryosu yazıyorum. Her zaman betiğin bulunduğu dizin olmak için geçerli çalışma dizini gerekir.

Varsayılan davranış, komut dosyasındaki geçerli çalışma dizininin çalıştırdığım kabuğun dizinidir, ancak bu davranışı istemiyorum.


/ Usr / bin gibi bir yere bir sarmalayıcı komut dosyasını (hardcoded) uygun dizine cd'ye yerleştirip komut dosyanızı yürütmeyi düşündünüz mü?
Dagg Nabbit

2
Komut dosyasının dizinine neden ihtiyacınız var? Muhtemelen altta yatan sorunu çözmenin daha iyi bir yolu var.
bstpierre

12
Ben sadece "açıkça istenmeyen" dediğiniz davranışın aslında tamamen gerekli olduğunu belirtmek istiyorum - Eğer çalıştırırsanız myscript path/to/fileben komut dosyası ne olursa olsun dizini ne olursa olsun, benim mevcut dizine göre yol / dosya / dosya değerlendirmek bekliyoruz Ayrıca, ssh remotehost bash < ./myscriptBASH SSS'den bahsedildiği gibi bir komut dosyası için ne olurdu ?
Gordon Davisson


3
cd "${BASH_SOURCE%/*}" || exit
caw

Yanıtlar:


656
#!/bin/bash
cd "$(dirname "$0")"

7
dirname '.' Windows altında bash kullanırken. Yani, Paul'ün cevabı daha iyi.
Tvaroh

7
Ayrıca '.' in OS OSX
Ben Clayton

4
Sembolik bir bağın parçası olursa, işlerin kırılabileceğini belirtmek gerekir $0. Komut dosyanızda, örneğin, ../../komut dosyasının konumunun üstündeki iki düzeyden oluşan dizine başvurmayı bekleyebilirsiniz, ancak sembolik bağlantılar oynatılıyorsa durum böyle olmayabilir.
Brian Gordon

20
Siz senaryoyu denilen Eğer ./script, .doğru dizin ve değişen .o da çok dizinde sona erecek scriptgeçerli çalışma dizini bulunan, yani.
ndim

6
Bunu gibi geçerli dizinden komut dosyası çalıştırırsanız bash script.sh, o zaman değeri $0olduğunu script.sh. cdKomutun sizin için "çalışmasının" tek yolu, başarısız komutları önemsememenizdir. Komut dosyanızın başarısız olan komutları geçmemesini sağlamak için set -o errexit(aka:) kullanırsanız set -e, bu cd script.shbir hata olduğu için ÇALIŞMAZ. Güvenilir [ cd "$(dirname ${BASH_SOURCE[0]})"
bash'a

322

Aşağıdakiler de çalışır:

cd "${0%/*}"

Sözdizimi, bu StackOverflow yanıtında ayrıntılı olarak açıklanmıştır .


17
Nasıl çalıştığına dair açıklama: stackoverflow.com/questions/6393551/…
kenorb

25
Yolda boşluk varsa tırnak işaretleri içine almayı unutmayın. yani cd "$ {0% / *}"
H.Rabiee

17
Komut dosyası ile çağrılırsa bu başarısız olur bash script.sh- $0sadece dosyanın adı olur
Chris Watts

17
Bu cevabın çok kısa ve öz olduğunu söyleyebilirim. Sözdizimi hakkında pek bir şey öğrenemezsiniz. Bunu nasıl okuyacağınıza dair bazı açıklamalar yardımcı olacaktır.
fraxture

2
Bu hile bir alt kabuk da ortaya çıkarmaz, bu yüzden hız düşkünleri için iyidir.
teknopaul

184

Aşağıdaki basit tek gömlekleri deneyin:


Tüm UNIX / OSX / Linux için

dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P)

darbe

dir=$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)

Not: Komutlarda, komut seçeneklerinin sonunu belirtmek için çift tire (-) kullanılır, böylece tire veya diğer özel karakterler içeren dosyalar komutu bozmaz.

Not: Bash'te ${BASH_SOURCE[0]}lehine kullanın $0, aksi takdirde yol kaynak yaparken kırılabilir ( source/ .).


Linux, Mac ve diğer * BSD için:

cd "$(dirname "$(realpath "$0")")";

Not: realpathvarsayılan olarak (Ubuntu gibi) en popüler Linux dağıtımına yüklenmelidir, ancak bazılarında eksik olabilir, bu yüzden yüklemeniz gerekir.

Not: Bash kullanıyorsanız ${BASH_SOURCE[0]}, lehine kullanın $0, aksi takdirde kaynak ( source/ .) kaynaklanırken yol kesilebilir .

Aksi takdirde böyle bir şey deneyebilirsiniz (mevcut ilk aracı kullanacaktır):

cd "$(dirname "$(readlink -f "$0" || realpath "$0")")"

Linux'a özgü:

cd "$(dirname "$(readlink -f "$0")")"

* BSD / Mac'te GNU okuma bağlantısını kullanma:

cd "$(dirname "$(greadlink -f "$0")")"

Not: Kurmuş olmanız gerekir coreutils(örn. 1. Homebrew , 2.'yi kurun brew install coreutils).


Bash

Bash'da bunu elde etmek için Parametre Genişletmelerini kullanabilirsiniz , örneğin:

cd "${0%/*}"

ancak komut dosyası aynı dizinden çalıştırılırsa çalışmaz.

Alternatif olarak bash'da aşağıdaki işlevi tanımlayabilirsiniz:

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

Bu işlev 1 argüman alır. Bağımsız değişken zaten mutlak bir yola sahipse, olduğu gibi yazdırın, aksi takdirde $PWDdeğişken + dosya adı bağımsız değişkenini ( ./önek olmadan ) yazdırın .

veya Debian .bashrcdosyasından alınan sürüm :

function realpath()
{
    f=$@
    if [ -d "$f" ]; then
        base=""
        dir="$f"
    else
        base="/$(basename "$f")"
        dir=$(dirname "$f")
    fi
    dir=$(cd "$dir" && /bin/pwd)
    echo "$dir$base"
}

İlişkili:

Ayrıca bakınız:

Mac'te GNU'nun readlink -f davranışını nasıl edinebilirim?


4
popüler olanlardan çok daha iyi bir cevap çünkü syslinks'i çözer ve farklı işletim sistemlerini açıklar. Teşekkürler!
Dennis

Bu cevap için teşekkürler. En üstteki cpMac'imde çalıştı ... ama - switch @kenorb komutunda ne yapar ?
TobyG

3
--Komutlarda komut seçeneklerinin sonunu belirtmek için çift ​​tire ( ) kullanılır, böylece tire veya diğer özel karakterler içeren dosyalar komutu bozmaz. Örneğin deneyin yoluyla dosya oluşturmak touch "-test"ve touch -- -testardından aracılığıyla dosyayı kaldırın, rm "-test"ve rm -- -test, ve farkı görmek.
kenorb

1
Realpath kullanımdan kaldırılmıştır: Ben eğer benim upvote kaldırmak istiyorum unix.stackexchange.com/questions/136494/...
LSH

1
@lsh realpathGNU değil, yalnızca Debian paketinin kullanımdan kaldırıldığını söylüyor realpath. Bunun net olmadığını düşünüyorsanız, bir düzenleme önerebilirsiniz.
kenorb

73
cd "$(dirname "${BASH_SOURCE[0]}")"

Bu kolay. İşe yarıyor.


1
Bu kabul edilen cevap olmalı. OSX ve Linux Ubuntu üzerinde çalışır.
David Rissato Cruz

5
B kodu diğer A komut dosyasından alındığında ve B komut dosyasına göre yollar kullanmanız gerektiğinde bu harika çalışır. Teşekkürler.
Enrico

5
Bu, Cygwin'de Windows'a dokunacak kadar talihsiz olanlarımız için de çalışır .
Bruno Bronosky

3
Veyacd "${BASH_SOURCE%/*}" || exit
caw

MacOS Mojave
Juan Boero

6

Kabul edilen cevap, içine başka bir yerde bağlanmamış komut dosyaları için iyi çalışır $PATH.

#!/bin/bash
cd "$(dirname "$0")"

Ancak komut dosyası bir sembolik bağlantıyla çalıştırılırsa,

ln -sv ~/project/script.sh ~/bin/; 
~/bin/script.sh

İçine Bu irade cd ~/bin/dizininde değil ~/project/muhtemelen Senaryonu kıracak dizin, amacı ise cdgöreli bağımlılıklar dahil etmektir~/project/

Symlink güvenli cevabı aşağıdadır:

#!/bin/bash
cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"

readlink -f potansiyel olarak sembolize edilmiş dosyanın mutlak yolunu çözmek için gereklidir.

Tırnak işaretleri potansiyel olarak boşluk içerebilecek dosya yollarını desteklemek için gereklidir (kötü uygulama, ancak bunun böyle olmayacağını varsaymak güvenli değildir)


4

Bu senaryo benim için çalışıyor gibi görünüyor:

#!/bin/bash
mypath=`realpath $0`
cd `dirname $mypath`
pwd

Pwd komut satırı, çalıştırdığım yerden bağımsız olarak komut dosyasının konumunu geçerli çalışma dizini olarak yansıtır.


3
realpathher yere kurulamaz. Bu OP'nin durumuna bağlı olarak önemli olmayabilir.
bstpierre

Sistemim yok realpathama readlinkbenzer gibi görünüyor.
sonraki duyuruya kadar duraklatıldı.

2
Hangi dağıtım varsayılan olarak realpath yüklü değil? Ubuntu'da var.
kenorb


1
cd "`dirname $(readlink -f ${0})`"

Cevabınızı açıklayabilir misiniz lütfen?
Zulu

1
Bu kod sorunu çözmeye yardımcı olsa da , soruyu neden ve / veya nasıl cevapladığını açıklamaz . Bu ek bağlamın sağlanması, uzun vadeli eğitim değerini önemli ölçüde artıracaktır. Hangi sınırlamalar ve varsayımlar dahil olmak üzere açıklama eklemek için lütfen yanıtınızı düzenleyin .
Toby Speight

-5
echo $PWD

PWD bir ortam değişkenidir.


5
Bu, komut dosyasının bulunduğu dizini değil, yalnızca denilen dizini verir.
dagelf

-6

Mevcut çalışma dizinini yazdırmanız gerekiyorsa, bunu takip edebilirsiniz.

$ vim test

#!/bin/bash
pwd
:wq to save the test file.

Yürütme izni verin:

chmod u+x test

Sonra komut dosyasını yürütün, ./testo zaman mevcut çalışma dizinini görebilirsiniz.


2
Soru, betiğin çalışma dizini değilse de dahil olmak üzere kendi dizininde çalışmasını sağlamaktı . Yani bu bir cevap değil. Neyse, neden sadece ... koşmak yerine ? Bana çok fazla boşa basmış gibi görünüyor. pwd
underscore_d
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.