Neden “cd” kabuk betiğinde çalışmıyor?


766

Geçerli dizini proje dizinime değiştirmek için küçük bir komut dosyası yazmaya çalışıyorum:

#!/bin/bash
cd /home/tree/projects/java

Bu dosyayı proj olarak kaydettik, yürütme izni ekledim chmodve kopyaladım /usr/bin. Bunu şöyle dediğimde proj, hiçbir şey yapmaz. Neyi yanlış yapıyorum?


10
siteler arası kopya: superuser.com/questions/176783/…
lesmana

Gelecekte her zaman pwdson satırda test etmeyi deneyebilirsiniz . Yani komut dosyası bitmeden önce çalışıp çalışmadığını kontrol edebilirsiniz ..
sobi3ch

5
@lesmana bu nasıl bir kopya?
aland

@aland OP Çünkü yaptığı değil çalışma dir onun için değişmez yüzden senaryoyu çalıştırmak aslında. cdkomut, komut dosyalarının içinde iyi çalışır, kendiniz deneyin.
Alexander Gonchiy

Yanıtlar:


634

Kabuk komut dosyaları bir alt kabuğun içinde çalıştırılır ve her alt kabuğun geçerli dizinin ne olduğuna ilişkin kendi kavramı vardır. cdBaşarılı, ancak en kısa sürede altkabuk çıkışları gibi, sen etkileşimli kabukta sırt ve hiç bir şey yoktur değişti.

Bu sorunu aşmanın bir yolu da takma ad kullanmaktır:

alias proj="cd /home/tree/projects/java"

7
Takma adlar, yönetmek veya değiştirmek için esnek değildir. Birçok cd durumunda, betikler daha iyi olabilir.
Thevs

16
İşlevler takma adlardan daha esnektir, bu yüzden takma adlar yeterli olmadığında sıraya girersiniz.
ephemient

4
MS-DOS'ta komut dosyalarının davranışı, çağrılan komut dosyasının çağıran komut kabuğunun dizinini (ve hatta sürücüsünü) değiştirebileceğidir. Ve bu Unix'in bu kusuru yok mu?
Jonathan Leffler

23
Jonathan: Bu doğru olsa da, bu gerçekten soruyla ilgili değil. Her liste için MS-DOS karşılık gelen eksiklikleri varsa SO cevapları iki kat daha uzun olurdu!
Greg Hewgill

17
Bu sorunu aşmanın başka bir yolu da komut dosyasını kaynaklamaktır: . my-scriptveya source my-script.
HelloGoodbye

503

Yanlış bir şey yapmıyorsun! Dizini değiştirdiniz, ancak yalnızca komut dosyasını çalıştıran alt kabuk içinde.

Komut dosyasını geçerli işleminizde "dot" komutuyla çalıştırabilirsiniz:

. proj

Ancak Greg'in önerisinin bu basit durumda takma ad kullanmasını tercih ederim.


95
.ayrıca hecelenir source, hangisini daha unutulmaz bulursanız seçin.
ephemient

47
@Ephemient: İyi puan kaynağı Neden çalıştığını açıklıyorKuruluşun gereklilik değil- çoğu zaman icat kaynağı olduğunu kanıtlıyor
Adam Liss

8
@ephemient: kaynağın C kabuğunda ve Bash'de kullanıldığına dikkat edin; POSIX veya Korn mermilerinde veya klasik Bourne kabuğunda desteklenmez.
Jonathan Leffler

2
"kaynak" Z kabuğunda kullanılır
Nathan Moos

1
@AdamLiss Harika çalışıyor, ancak bir dezavantajı var - bir şekilde kaynak / nokta komutu, TAB tuşuyla komut dosyasının / komutun adını otomatik olarak tamamlama olasılığını devre dışı bırakır. SEKME tuşu ile argümanlar / girdi eklemek hala mümkündür, ancak maalesef komutun adı doğrudan girilmelidir. Bu durumda SEKME tuşunu nasıl çalıştıracağınızı biliyor musunuz?
Rafal

215

cdSenaryonuzun teknik çalışmış o senaryoyu ran kabuk dizini değiştikçe, ama bu senin interaktif kabuğundan çatallı ayrı süreç oldu.

Bu sorunu çözmek için Posix uyumlu bir yol, kabuk çağrılan bir komut komut dosyası yerine bir kabuk yordamı tanımlamaktır .

jhome () {
  cd /home/tree/projects/java
}

Bunu sadece yazabilir veya çeşitli kabuk başlangıç ​​dosyalarından birine koyabilirsiniz.


6
Katılıyorum, bu en iyi cevap, çarptı. Ayrıca, takma ad bazı durumlarda uygun olabilir, ancak bir komut dosyasında cd kullanmaya çalışıyorsa ve başka bir şey eklemek isterse takma ad işe yaramaz.
Justin Buser

4
Bu bir çözüm gibi görünüyor! Ve ben uygulamaya çalışıyorum, ama performans değil :( İşte benim senaryom: #! / Bin / bash jhome () {echo "lütfen" cd / ev echo "iş"} jhome
Gant Laborde

1
@GantMan, bunu ~ / .bashrc
Jackie Yeh

3
Ayrıca bir argüman (veya iki ...) kullanabilirsiniz, yani:jhome(){ cd /home/tree/projects/$1; }
irbanana

1
Bu doğru yol olmalı, örneğin "-" gibi özel karakterlerin kullanılmasını mümkün kılar.
bangkokguy

159

cdKomut dosyasının kabuk içinde yapılır. Komut dosyası sona erdiğinde, o kabuk çıkar ve sonra bulunduğunuz dizinde kalırsınız. Komut dosyasını "kaynaklayın", çalıştırmayın. Onun yerine:

./myscript.sh

yapmak

. ./myscript.sh

(Komut dosyası adından önceki nokta ve boşluğa dikkat edin.)


2
Bu harika ve muhtemelen bilmek iyidir. İkincisi tam olarak ne yapar (nasıl çalışır)? Bu muhtemelen bu iş parçacığındaki en iyi çözümdür.
Jonah

2
fwiw, Adam Liss'in cevabının yorum bölümünde, geçici “ne” sorusuna cevap veriyor. dır-dir. Aynı şeysource
g19fanatic

1
Dikkatli olun, "kaynak" bir bashizmdir. yani tire (/ bin / sh için Debian varsayılanı) desteklemezken "." beklendiği gibi çalışır.
allo

Mükemmel cevap! ayrıca myscript.sh$ PATH içindeki bir dizindeyse, tam yolu belirtmeden herhangi bir yerden kaynak yapabilirsiniz.
CodeBrew

Bu benim için en iyisi oldu. Bu çözüm en basitidir (+1).
HuserB1989

96

Seçilen bir dizine cd yazacak bir bash betiği yapmak için:

Komut dosyası oluşturma

#! / Bin / sh
# dosya: / komut dosyaları / cdjava
#
cd / ana sayfa / askgelal / projeler / java

Ardından başlangıç ​​dosyanızda bir takma ad oluşturun.

#! / Bin / sh
# file /scripts/mastercode.sh
#
takma ad cdjava = '. / Komut / cdjava'

  • Tüm takma adlarımı ve özel fonksiyonlarımı döktüğüm bir başlangıç ​​dosyası oluşturdum.
  • Sonra her önyükleme ayarlamak için bu dosyayı benim .bashrc içine kaynak.

Örneğin, bir ana diğer ad / işlevler dosyası oluşturun: /scripts/mastercode.sh
(Diğer adı bu dosyaya yerleştirin.)

Sonra .bashrc dosyanızın sonunda :

kaynak /scripts/mastercode.sh



Şimdi java dizininize cd kolay, sadece cdjava yazın ve oradasınız.


2
bir alt kabukta yürütülmediğinden (ve çalıştırılamadığından) dosya mastercode.shshabang ( #!/bin/sh) 'a ihtiyaç duymaz . Ama aynı zamanda, bu dosyanın kabuk "lezzet" belgelemek gerekir; örneğin, ksh veya bash (veya (t) csh / zsh, vb.) ve neredeyse kesinlikle değil sh. Ben genellikle bu iletişim için bir yorum (ama shebang değil) ekleyin; örn., "bu dosyanın kaynağı (bash'tan), kabuk komut dosyası olarak çalıştırılmaması amaçlanmıştır."
michael

Başka bir ipucu (bash için): komut dosyanızda değişkenler kullanıyorsanız, komut dosyası sourced olarak (aracılığıyla alias), bu değişkenler kabuk ortamınıza sızacaktır. Bundan kaçınmak için, komut dosyasının tüm işlerini bir işlevde yapın ve komut dosyasının sonunda çağırın. İşlev içinde herhangi bir değişkeni bildirin local.
Rhubbarb

Ubuntu'da sadece ~ / .bash_aliases oluşturun (zaten yoksa). Ardından diğer adlarınızı buraya ekleyin, terminali yeniden başlatın ve işiniz bitti.
Vlad

51

.Geçerli kabuk ortamında bir komut dosyası yürütmek için kullanabilirsiniz :

. script_name

veya alternatif olarak, daha okunabilir ancak kabuğa özgü takma adı source:

source script_name

Bu, alt cdkabuktan kaçınır ve değişkenlerin veya yerleşiklerin (dahil ) geçerli kabuğu etkilemesini sağlar.


38

Jeremy Ruten'in symlink kullanma fikri, başka bir yanıtı geçmeyen bir düşünceyi tetikledi. kullanın:

CDPATH=:$HOME/projects

Önde gelen kolon önemlidir; geçerli dizinde 'dir' dizini varsa, ' cd dir' başka bir yerde atlamak yerine bu dizine değişecektir. Değer gösterildiği gibi ayarlandığında şunları yapabilirsiniz:

cd java

ve geçerli dizinde java adında bir alt dizin yoksa, sizi doğrudan $ HOME / projects / java adresine götürür - takma ad yok, komut dosyası yok, şüpheli yürütme veya nokta komutu yok.

$ HOME'um / Users / jleffler; benim $ CDPATH:

:/Users/jleffler:/Users/jleffler/mail:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work

31

exec bashSonunda kullanın

Bir bash betiği mevcut ortamında ya da çocuklarının ortamında çalışır, ancak asla ana ortamında çalışmaz.

Ancak, bu soru sık sık sorulur çünkü yürütüldükten sonra belirli bir dizinde (yeni) bir bash isteminde kalmak ister başka bir dizinden bir bash betiğinin .

Bu durumda, komut dosyasının sonunda bir alt bash örneği çalıştırın :

#!/usr/bin/env bash
cd /home/tree/projects/java
exec bash

16
Bu yeni bir alt kabuk oluşturur. Eğer yazdığınızda exitBu komut dosyasını ran kabuk dönecektir.
üçlü

1
Komut dosyası birkaç kez çağrıldığında iç içe geçmiş kabuklar oluşturur ve ben birçok kez 'çıkış' yazmanız gerekir. Bu bir şekilde çözülebilir mi?
VladSavitsky

Diğer yanıtlara bakın: bir takma ad kullanın, "pushd / popd / dirs" kullanın veya "source" kullanın
qneill

25

Kodumu kullanarak çalışıyorum. <your file name>

./<your file name> doz çalışmaz, çünkü terminaldeki dizini değiştirmez, sadece o betiğe özgü dizini değiştirir.

İşte benim programım

#!/bin/bash 
echo "Taking you to eclipse's workspace."
cd /Developer/Java/workspace

İşte terminalim

nova:~ Kael$ 
nova:~ Kael$ . workspace.sh
Taking you to eclipe's workspace.
nova:workspace Kael$ 

2
. somethingVe ./something?? arasındaki fark nedir ? Bu cevap benim için çalıştı ve nedenini anlamıyorum.
Dracorat

. somethingkomut dosyasını herhangi bir konumdan çalıştırmanıza izin verir ./something, dosyanın depolandığı dizinde olmanızı gerektirir.
Projjol


Noktayı shebang hattına koyabilir misin? #!. /bin/bash?
Sigfried


12

Bir kabuk betiğini tetiklediğinizde, o kabuğun ( ) yeni bir örneğini çalıştırır /bin/bash. Böylece, betiğiniz bir kabuk oluşturur, dizini değiştirir ve çıkar. cdKabuk betiği içine başka bir yol (ve bu tür diğer komutlar), başlatıldıkları kabukları etkilemez veya bunlara erişemez.


11

Benim durumumda ben aynı dizini değiştirmek için çok kez gerekiyordu. Bu yüzden benim .bashrc (ubuntu kullanıyorum)

1 -

$ nano ~. / bashrc

 function switchp
 {
    cd /home/tree/projects/$1
 }

2-

$ source ~ / .bashrc

3 -

$ switchp java

Doğrudan yapacak: cd / home / tree / projects / java

Umarım yardımcı olur!


1
@WM Sonunda doğrudan proje ağacına gitmek için herhangi bir parametre olmadan "$ switchp" yapabilirsiniz
workdreamer

2
@workdreamer Yukarıda açıkladığınız işlev yaklaşımı, sistemimde aynı üst klasöre sahip alt klasörlere girerken biraz sorun çözdü. Teşekkür ederim.
WM

10

Aşağıdakileri yapabilirsiniz:

#!/bin/bash
cd /your/project/directory
# start another shell and replacing the current
exec /bin/bash

DÜZENLEME: Bu, sonraki mermilerin oluşturulmasını önlemek için de 'noktalı' olabilir.

Misal:

. ./previous_script  (with or without the first line)

1
Bu, birkaç çalıştırmadan sonra oldukça dağınık hale gelir exit. Örneğin, kabuktan çıkmak için birkaç kez (veya ctrl + d) gerekir. Örneğin, bir takma ad çok daha temizdir (shell komutu bir dizin çıkarsa bile ve cd'ler çıkış - takma ad bir şey = "cd getnewdirectory.sh")
dbr

'Exec' not edin. Eski kabuğun yerini alır.
Thevs

2
Exec, komut dosyasını çalıştıran kabuğun değil, yalnızca cd komutunu çalıştıran alt kabuğun yerini alır. Senaryoyu noktalasaydın, doğruydun.
Jonathan Leffler

'Noktalı' yapın - sorun değil. Çözüm önerdim. Bunu nasıl başlattığınıza bağlı değil.
Thevs

2
Hehe, sadece cd komutuyla tek satırlık komut dosyasını 'noktalamak' için daha iyi olduğunu düşünüyorum :) Yine de cevabımı koruyacağım ... Bu yanlış aptalca soruya doğru aptalca cevap olacak :)
Thevs

7

Geçerli dizininiz aynı kalırken yalnızca betiğin dizini değiştirir.

Bunun yerine sembolik bir bağlantı kullanmak isteyebilirsiniz . Bir dosyaya veya dizine "kısayol" yapmanıza izin verir, bu nedenle sadece böyle bir şey yazmanız gerekir cd my-project.


Her dizinde bu sembolik bağlantının olması sıkıntı yaratacaktır. Symlink'i $ HOME'a koymak ve sonra 'cd ~ / my-project' yapmak mümkün olacaktır. Açıkçası CDPATH kullanmak daha kolaydır.
Jonathan Leffler

7

Daha dinamik olabilecek bir şey yapmak için Adam & Greg'in takma adını ve nokta yaklaşımlarını birleştirebilirsiniz.

alias project=". project"

Şimdi proje takma adını çalıştırmak, alt kabuk yerine aksine mevcut komut dosyasında proje komut dosyasını yürütecektir.


Tam olarak tüm senaryomu korumak ve bash'den çağırmak ve mevcut oturumu korumak için tam olarak ihtiyacım olan şey bu - MÜKEMMEL cevap.
Matt The Ninja

7

Bir takma ad ve bir komut dosyası birleştirebilirsiniz,

alias proj="cd \`/usr/bin/proj !*\`"

ancak betiğin hedef yolun yankılanması koşuluyla. Bunların komut dosyası adını çevreleyen geri tıklamalar olduğunu unutmayın. 

Örneğin, komut dosyanız

#!/bin/bash
echo /home/askgelal/projects/java/$1

Bu tekniğin avantajı, betiğin herhangi bir sayıda komut satırı parametresi alabilmesi ve muhtemelen karmaşık mantık tarafından hesaplanan farklı hedefler yaymasıdır.


3
neden? şunu kullanabilirsiniz: proj() { cd "/home/user/projects/java/$1"; }=> proj "foo"(veya proj "foo bar"boşluklarınız varsa <=) ... hatta çift (örneğin): proj() { cd "/home/user/projects/java/$1"; shift; for d; do cd "$d"; done; }=> proj a b c=> cdiçine/home/user/projects/java/a/b/c
michael


5

~ / .Bash_profile dosyanızda. sonraki işlevi ekle

move_me() {
    cd ~/path/to/dest
}

Terminali yeniden başlatın ve yazabilirsiniz

move_me 

ve hedef klasöre taşınacaksınız.


3

Operatörü && kullanabilirsiniz:

cd myDirectory && ls


Downvote: Bu, asıl soruyu burada cevaplamaya çalışmaz. Komut isteminde iki komut çalıştırabilirsiniz ( &&ikincisinin ilkinde koşullu olmasını istiyorsanız veya yalnızca aralarında ;veya yeni satırda), ancak bunu bir komut dosyasına yerleştirmek sizi "ana kabuk neden kullanmıyor? cdbaşarılı olduğunda yeni dizini ? "
üçlü

3

Çalıştırmak istediğiniz komut dosyasını kaynaklamak bir çözüm olsa da, bu komut dosyasının geçerli kabuğunuzun ortamını doğrudan değiştirebileceğini bilmelisiniz. Ayrıca artık argüman iletmek de mümkün değil.

Bunu yapmanın başka bir yolu da, betiğinizi bash'da bir işlev olarak uygulamaktır.

function cdbm() {
  cd whereever_you_want_to_go
  echo "Arguments to the functions were $1, $2, ..."
}

Bu teknik autojump tarafından kullanılır: http://github.com/joelthelion/autojump/wiki size kabuk dizini yer işaretlerini öğrenmek için kullanılır.


3

Sizde aşağıdaki gibi bir işlev oluşturabilirsiniz .bash_profileve sorunsuz çalışır.

Aşağıdaki işlev, proje olan isteğe bağlı bir parametre alır. Örneğin,

cdproj

veya

cdproj project_name

İşte fonksiyon tanımı.

cdproj(){
    dir=/Users/yourname/projects
    if [ "$1" ]; then
      cd "${dir}/${1}"
    else
      cd "${dir}"
    fi
}

Kaynağını unutma .bash_profile


1
takma
addan

Bu çözüm, sadeliği ve esnekliği ile mükemmeldir.
Kjartan

3

Bu istediğinizi yapmalı. İlgilenilen dizine geçin (komut dosyasının içinden) ve sonra yeni bir bash kabuğu oluşturun.

#!/bin/bash

# saved as mov_dir.sh
cd ~/mt/v3/rt_linux-rt-tools/
bash

Bunu çalıştırırsanız, sizi ilgili dizine götürür ve çıktığınızda sizi orijinal yerine geri getirir.

root@intel-corei7-64:~# ./mov_dir.sh

root@intel-corei7-64:~/mt/v3/rt_linux-rt-tools# exit
root@intel-corei7-64:~#

Bu, çıktığınızda ( CTRL+ d) orijinal dizininize geri dönmenizi sağlar


3
Yeni bir bashın ortaya çıkması, geçmişinizi kaybettiğiniz anlamına gelir ve yeni başlayacaktır.
Tisch

2

LOOOOOng zaman sonra, ama aşağıdakileri yaptım:

case adlı bir dosya oluştur

aşağıdakileri dosyaya yapıştırın:

#!/bin/sh

cd /home/"$1"

kaydedin ve sonra:

chmod +x case

Ayrıca bir takma ad oluşturdum .bashrc:

alias disk='cd /home/; . case'

şimdi yazarken:

case 12345

aslında yazıyorum:

cd /home/12345

'Case' ifadesinden sonra herhangi bir klasörü yazabilirsiniz:

case 12

case 15

case 17

hangi yazmak gibi:

cd /home/12

cd /home/15

cd /home/17

sırasıyla

Benim durumumda yol çok daha uzun - bu adamlar daha önce ~ bilgi ile özetledi.


1
Diğer cdadda gereksiz ve yetersiz; takma ad basitçe olmalıdır '. ~ / case` yerine. Ayrıca case, ayrılmış anahtar kelime, bir isim için öylesine oldukça kötü bir seçimdir.
tripleee

1

Komut dosyasına ihtiyacınız yoktur, yalnızca doğru seçeneği belirleyin ve bir ortam değişkeni oluşturun.

shopt -s cdable_vars

Gözlerinde farklı ~/.bashrcsağlayan cdortam değişkenleri içeriğine.

Böyle bir ortam değişkeni oluşturun:

export myjava="/home/tree/projects/java"

ve şunları kullanabilirsiniz:

cd myjava

Diğer alternatifler .


0

Kabuğu olarak balık kullanıyorsanız , en iyi çözüm bir işlev oluşturmaktır. Örnek olarak, orijinal soru göz önüne alındığında, aşağıdaki 4 satırı kopyalayabilir ve balık komut satırınıza yapıştırabilirsiniz:

function proj
   cd /home/tree/projects/java
end
funcsave proj

Bu, işlevi yaratacak ve daha sonra kullanmak üzere kaydedecektir. Projeniz değişirse, yeni yolu kullanarak işlemi tekrarlayın.

İsterseniz, aşağıdakileri yaparak işlev dosyasını el ile ekleyebilirsiniz:

nano ~/.config/fish/functions/proj.fish

ve metni girin:

function proj
   cd /home/tree/projects/java
end

ve son olarak çıkmak için ctrl + x tuşlarına basın ve ardından değişikliklerinizi kaydetmek için geri dönün.

( NOT: funcsave kullanmanın ilk yöntemi sizin için proj.fish dosyasını oluşturur ).


0


Github.com/godzilla/bash-stuff dizin değiştirme yönetmek için p adlı basit bir bash komut dosyası var
sadece komut dosyası yerel bin dizini (/ usr / local / bin)
koymak ve koymak

alias p='. p'

.bashrc'nizde


bu ne yapar? Kendini yinelemeli olarak çalıştırır gibi görünüyor, ancak bunu yapmadan önce çalıştırdığından eminim;)
Ryan Taylor


0

Bu eski bir soru, ama burada bu numarayı görmediğime gerçekten şaşırdım

Bunun yerine kullanmanın cd kullanabilirsiniz

export PWD=the/path/you/want

Alt kabuklar oluşturmaya veya takma ad kullanmaya gerek yok.

/ Path / you / want öğesinin var olduğundan emin olmak sizin sorumluluğunuzdadır.


Maalesef işe yaramadı.
ttfreeman

0

Diğer yanıtlarda açıklandığı gibi, dizini değiştirdiniz, ancak yalnızca komut dosyasını çalıştıran alt kabukta . bu ana kabuğu etkilemez.

Bir çözüm bash script ( ) yerine bash işlevlerini kullanmaktır sh; bash kodunuzu bir fonksiyona yerleştirerek. Bu, işlevi bir komut olarak kullanılabilir hale getirir ve daha sonra, bu bir alt işlem olmadan yürütülür ve böylece herhangi bir cdkomut arayan kabuğunu etkiler.

Bash fonksiyonları:

Bash profilinin bir özelliği, uygulama / komutları çalıştırdığınız gibi terminalde veya bash komut dosyalarında çalıştırılabilen özel işlevleri depolamaktır ve bu da uzun komutlar için kısayol olarak kullanılabilir.

İşlev etkin sisteminizi yaygın bir şekilde yapmak için, birkaç dosyanın sonunda işlevinizi kopyalamanız gerekir.

/home/user/.bashrc
/home/user/.bash_profile
/root/.bashrc
/root/.bash_profile

Bu sudo kwrite /home/user/.bashrc /home/user/.bash_profile /root/.bashrc /root/.bash_profiledosyaları hızlı bir şekilde düzenleyebilir / oluşturabilirsiniz

Nasıl :

Bash komut dosyası kodunuzu bash profil dosyanızın sonundaki yeni bir işlevin içine kopyalayın ve terminalinizi yeniden başlatın, daha sonra cddveya yazdığınız işlev ne olursa olsun çalıştırabilirsiniz .

Senaryo Örneği

Kısayol yapma cd ..ilecdd

cdd() {
  cd ..
}

ls kısayolu

ll() {
  ls -l -h
}

ls kısayolu

lll() {
  ls -l -h -a
}

-2

Çizgileri ters eğik çizgi ile sonlandırırsanız, aynı alt kabuktaki bazı satırları yürütebilirsiniz.

cd somedir; \
pwd
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.