Neden `` `` cd` `komutu için çalışmaz? 'Cd` için de yürütülebilir dosyayı bulamıyorum!


30

Denedim which cdve bir yol vermedi ancak bunun yerine çıkış kodunu 1 (kontrol edildi echo $?) verdi. Coreutil cdkendisi çalışıyor, bu yüzden çalıştırılabilir orada olmalı, değil mi? Ayrıca bir findfor koştum cd, ancak gösterilen bir yürütülebilir dosya yoktu. O zaman nasıl uygulanır?

Güncelleştirme:

Bunu başka bir gönderide sormalı mıyım bilmiyorum ama burada iyi olduğunu düşündüğümden beri yazıyı genişletiyorum (?) ... Cevap aslında oldukça basitti, bunun için çalıştırılabilir bir şey yok - çünkü bir yerleşik - Ancak bazı yerleşiklerin (Fedora'daki bash kabuğu) çalıştırılabilir dosyaları olduğunu gördüm! Yani yerleşik -> çalıştırılabilir dosya yok sanırım? Belki de yerleşiklerin gerçekte ne olduğunu açıklayan bir cevap (yerleşik komutlar?), Burada asıl mesele budur, daha cdçok şeye odaklanmak yerine ... Daha önce yayınlanan bazı iyi bağlantılar, yerleşiklerin program olmadığını gösteriyor ... peki bunlar ne? Nasıl çalışıyorlar? Bunlar sadece kabuğun işlevi mi yoksa ipliği mi?


1
Bu cevabı oku . Bu typekomutun kullanılması önerilir
c0rp

7
Nedencd bir yerleşik olması gerektiğine ilişkin bu Soru ve Cevap bölümüne bakınız : Neden cd bir program değil? ve neden typebu daha iyidir which: Neden "hangisini" kullanmıyorsun? Ne kullanmalı?
terdon

Burada benzer soru: askubuntu.com/q/613470/178596
Wilf

Yanıtlar:


46

Komut cdçalıştırılabilir olamaz

Bir kabukta, cd"çalışma dizini" (CWD) değiştirmek için "başka bir dizine gitmek" veya daha resmi olarak kullanılır. Bunu harici bir komut olarak uygulamak imkansız:

Dizin bir işleme ait

Kıvrımlı çalışma dizini, dosyalara erişmek için kullanılabilecek bir tam yol elde etmek üzere göreceli yolları yorumlamak için kullanılan dizindir. Göreceli yollar birçok yerde kullanılır ve bir işlemdeki yorum başka bir işlemi etkilememelidir.
Bu nedenle, her işlem kendi geçerli çalışma dizinine sahiptir.

cdÖrneğin, kabuk işleminin mevcut çalışma dizinini değiştirmekle ilgilidir bash.

Harici bir komut olsaydı, bu yürütülebilir dosyayı çalıştıran, yoldaki bir yürütülebilir dosya, mevcut kabuğunkine etki etmeden kendi çalışma diziniyle bir işlem yaratabilirdi. Harici komut dizini değiştirse bile, dış işlem çıktığında bu değişiklik ortadan kalkar.

Kabuk yerleşik komutları

Bu nedenle, görev için harici bir komut çalıştırmanın bir anlamı yoktur cd. Komut cdşu anda çalışan kabuk işleminde bir değişiklik yapmalı.

Bunu yapmak için, kabuğun bir "yerleşik komutu" dir.

Yerleşik komutlar, dış komutlara benzeyen, ancak kabukta uygulanan komutlardır (bu yüzden çekirdek elemanların bir cdparçası değildir). Bu komutun kabuğun durumunu değiştirmesine izin verir, bu durumda chdir()see (see man 2 chdir);

hakkında which

Şimdi, başlık sorusunun cevabı kolaydır:
Yürütülebilir komut whichbize cd'nin yerleşik bir komut olduğunu söyleyemez, çünkü yürütülebilir bir komut yerleşikler hakkında hiçbir şey bilmez.

Alternatif type -a

Alternatif olarak whichkullanabilirsiniz type -a; Yürütülebilir komutları ve yerleşikleri görebilir; Ek olarak, takma adları ve işlevleri görür - kabukta da uygulanır:

$ type -a cd
cd is a shell builtin
$ type -a type
type is a shell builtin
$ type -a which
which is /usr/bin/which
which is /bin/which

1
Harika bir açıklama!
SaltyNuts

3
Şu anda kabul edilen cevaptan çok daha iyi - bu neden cd bir kabuğun yerleşik olduğunu açıklıyor .
Lily Chung,

28

cda, POSIX zorunlu kabuk yerleşik:

Basit bir komut, bir komut ismiyle ve isteğe bağlı bir argüman listesiyle sonuçlanırsa, aşağıdaki eylemler gerçekleştirilir:

  1. Komut adı eğik çizgi içermiyorsa, aşağıdaki sıradaki ilk başarılı adım gerçekleşir:
    ...
    • Komut adı, aşağıdaki tabloda listelenen bir yardımcı programın adıyla eşleşiyorsa, bu yardımcı program çağrılmalıdır.
      ...
      cd
      ...
    • Aksi takdirde, komut PATH kullanımı için aranır ...

Bu açıkça bir yerleşik olması gerektiğini söylese de , tarifnamede şöyle açıklanmaktadırcd :

Cd mevcut kabuk yürütme ortamını etkilediğinden, her zaman düzenli yerleşik bir kabuk olarak sağlanır.

Gönderen bashmanuel :

Aşağıdaki kabuk yerleşik komutları Bourne Kabuğundan miras alınır. Bu komutlar POSIX standardında belirtildiği şekilde uygulanır.
...

cd
       cd [-L|[-P [-e]]] [directory]

Sanırım cdyerleşik olması gerekmeyen bir mimariyi düşünebilirsin . Ancak, bir yerleşikin ne anlama geldiğini görmek zorundasınız. Bazı komutlar için bir şeyler yapmak üzere kabuğa özel bir kod yazarsanız, bir yerleşik yapıya yakınlaşırsınız. Ne kadar çok yaparsanız, basitçe bir yerleşime sahip olmak o kadar iyidir.

Örneğin, alt işlemlerle iletişim kurmak için kabuğun IPC'sine sahip olabilirsiniz cdve dizinin varlığını ve erişim izninizin olup olmadığını kontrol etmenizi sağlayan bir program olur ve ona kabukla iletişim kurmasını söyler. dizin. Bununla birlikte, sizinle iletişim kuran sürecin bir çocuk olup olmadığını (veya özel bir dosya tanıtıcısı, paylaşılan hafıza vb. Gibi yalnızca çocuklarla özel iletişim araçları kullanın) ve işlemin gerçek olup olmadığını kontrol etmeniz gerekir. güvenilir cdprogramı veya başka bir şeyi çalıştırmak. Bu bir sürü solucan.

Veya sistem çağrısı cdyapan bir programınız olabilir chdirve yeni kabuğa uygulanan tüm geçerli ortam değişkenleriyle yeni bir kabuk başlatır ve ardından bittiğinde üst kabuğunu (bir şekilde) öldürür. 1

Daha da kötüsü, bir işlemin diğer işlem ortamlarını değiştirebileceği bir sisteme bile sahip olabilirsiniz (teknik olarak hata ayıklayıcılarla yapabileceğinizi düşünüyorum). Bununla birlikte, böyle bir sistem çok ama çok savunmasız olacaktır.

Kendinizi bu tür metotları güvence altına almak için giderek daha fazla kod ekleyeceksiniz ve basitçe bir yerleşik yapmak oldukça daha kolaydır.


Bir şeyin çalıştırılabilir olması, yerleşik olmasını engellemez. Konuşma konusu olan mesele:

echo ve test

echove testPOSIX zorunlu görev programlarıdır ( /bin/echove /bin/test). Oysa hemen hemen her popüler kabuğun bir yapısı vardır echove test. Benzer şekilde, killbir program olarak mevcut yerleşiktir. Diğerleri şunlardır:

  • sleep (yaygın değil)
  • time
  • false
  • true
  • printf

Bununla birlikte, bir komutun yerleşik olmayan bir şey olamayacağı bazı durumlar vardır. Bunlardan biri cd. Genellikle, tam yol belirtilmezse ve komut adı bir yerleşikin adıyla eşleşiyorsa, o komuta uygun bir işlev çağrılır. Kabuğa bağlı olarak, yapının ve çalıştırılabilir dosyanın davranışı farklı olabilir (bu özellikle çılgınca farklı davranışlara sahip olan bir sorundurecho . tam yol ve gibi değişkenler ayarlayın (o zaman bile gerçek bir garanti yoktur).POSIXLY_CORRECT

Teknik olarak, aynı zamanda bir kabuk olan ve yerleşik olarak her komutu olan bir işletim sistemi sağlamanızı önleyen hiçbir şey yoktur. Bu aşırı uç yakın, monolitik BusyBox . BusyBox, (adı verilen isme bağlı olarak) bir Almquist Shell ( ) dahil olmak üzere 240 programdan herhangi biri gibi davranabileceği tek bir ikilidir ash. BusyBox'ı PATHçalıştırırken ayırırsanız ash, BusyBox'ta bulunan programlara a belirtmeden erişebilirsiniz PATH. Onlar kabuk yerleşiklerine yaklaşıyorlar, ancak kabuğun kendisi BusyBox'a özgü bir yerleşik.


Örnek olay : Debian Almquist Shell ( dash)

dashKaynağa bakarsanız , yürütme ipliği şunun gibi bir şeydir (elbette, borular ve diğer şeyler kullanıldığında ilave işlevlerle birlikte):

maincmdloopevaltreeevalcommand

evalcommandsonra findcommandkomutun ne olduğunu belirlemek için kullanır . Bir yerleşik ise, o zaman :

 case CMDBUILTIN:
     if (spclbltin > 0 || argc == 0) {
         poplocalvars(1);
         if (execcmd && argc > 1)
             listsetvar(varlist.list, VEXPORT);
     }
     if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
         if (exception == EXERROR && spclbltin <= 0) {
             FORCEINTON;
             break;

cmdentry.u.cmdbir struct( struct builtincmd), üyeleri bir işlev gösterici, tipik bir imza ile bir main: (int, char **). evalbltinFonksiyon aramalar (yerleşik olup olmadığına bağlı olarak evalya komut ya da değil) evalcmd, veya bu fonksiyon işaretçi. Gerçek fonksiyonlar çeşitli kaynak dosyalarında tanımlanmıştır. echo, örneğin :

int
echocmd(int argc, char **argv)
{
    int nonl;

    nonl = *++argv ? equal(*argv, "-n") : 0;
    argv += nonl;

    do {
        int c;

        if (likely(*argv))
            nonl += print_escape_str("%s", NULL, NULL, *argv++);
        if (nonl > 0)
            break;

        c = *argv ? ' ' : '\n';
        out1c(c);
    } while (*argv);
    return 0;
}

Bu bölümdeki kaynak koduna olan tüm bağlantılar satır numarası bazındadır, bu nedenle önceden haber verilmeksizin değiştirilebilir.


1 POSIX sistemlerinde cdçalıştırılabilir bir dosya var .


Kenar notu:

Unix ve Linux'ta kabuk davranışı ile ilgilenen birçok mükemmel yazı var. Özellikle:

Şimdiye kadar listelenen sorularda bir model farketmediyseniz, neredeyse hepsi Stéphane Chazelas'ı içerir .


4
cdYardım metnini help cd(tüm kabuk yerleşik komutları için aynı şey) alabileceğinizi unutmayın
Sylvain Pineau

@SylvainPineau, bash kılavuzuna bağlı olmama rağmen, bu tavsiye genellikle zsh gibi diğer mermiler için geçerli değildir.
muru

Gerçekten helpde bir bash yerleşimidir (zsh için, bu run-help cd)
Sylvain Pineau

POSIX şartnamesindeki bağlantılı açıklama açıkça cdbunun kabuğun içinde olması gerektiği anlamına gelmez ... ama UNIX'te proses özelliklerinin ve bunların transferlerinin cdbir kabuk yerleşik olarak nasıl işlediğine dayanarak yapılır . Bkz Volker Siegel cevap .
pabouk

@pabouk gerçekten (buna bir yardımcı program diyor) ve sonra şöyle devam ediyor: "cd, mevcut kabuk yürütme ortamını etkilediğinden, her zaman düzenli yerleşik bir kabuk olarak sağlanır."
muru

8

cdHiçbiri için çalıştırılabilir bir dosya bulamıyorsunuz .

cdkabuğunuzun içsel bir emridir (örn. bash).


7

from man which:

Mevcut ortamda çalıştırılacak olan dosyaların (veya linklerin) dosya adlarını döndüren argümanları kesinlikle POSIX uyumlu bir kabuk içinde komut olarak verildi. Bunu, PATH'yi, bağımsız değişkenlerin adlarıyla eşleşen yürütülebilir dosyalar için arayarak yapar. Sembolik bağları takip etmez.

Açıklamasından görebileceğimiz whichgibi, sadece kontrol ediyor PATH. Yani, eğer bazılarını uygularsan bash function, sana hiçbir şey göstermeyecek. İle birlikte komutu kullanmak daha iyidir .typewhich

Örneğin, Ubuntu lskomutunda takma ad ls --color=auto.

$ type ls
ls is aliased to `ls --color=auto'

$ which ls
/bin/ls

Ve eğer test işlevini uygularsanız hello:

$ function hello() { for i in {1,2,3}; do echo Hello $i;done }
$ which hello

whichhiçbir şey göstermez. Ancak type:

$ type hello
hello is a function
hello () 
{ 
    for i in {1,2,3};
    do
        echo Hello $i;
    done
}

Senin durumunda:

$ type cd
cd is a shell builtin

Bu , içinde yerleşikcd bir kabuk olduğu anlamına gelir bash. Tüm bash yerleşimleri man bash, SHELL BUILTIN KOMUTLARI bölümünde,

SHELL BUILTIN COMMANDS
       Unless otherwise noted, each builtin command documented in this section
       as accepting options preceded by - accepts -- to signify the end of the
       options.   The  :, true, false, and test builtins do not accept options
       and do not treat -- specially.  The exit, logout, break, continue, let,
       and  shift builtins accept and process arguments beginning with - with‐
       out requiring --.  Other builtins that accept  arguments  but  are  not
       specified  as accepting options interpret arguments beginning with - as
       invalid options and require -- to prevent this interpretation.


1
Belki daha fazla vurgulanması gerekir: Kullanmayın which, kullanmayın type.
üçlü
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.