cd
jest wbudowaną powłoką z mandatem POSIX :
Jeśli proste polecenie daje nazwę polecenia i opcjonalną listę argumentów, należy wykonać następujące czynności:
- Jeśli nazwa polecenia nie zawiera żadnych ukośników, nastąpi pierwszy udany krok w następującej kolejności:
...
- Jeśli nazwa polecenia jest zgodna z nazwą narzędzia wymienionego w poniższej tabeli, narzędzie to należy wywołać.
...
cd
...
- W przeciwnym razie polecenie należy wyszukać za pomocą ŚCIEŻKI ...
Chociaż nie mówi to wyraźnie, że musi to być wbudowany, specyfikacja mówi dalej w opisiecd
:
Ponieważ cd wpływa na bieżące środowisko wykonywania powłoki, zawsze jest udostępniany jako zwykła wbudowana powłoka.
Z bash
instrukcji :
Następujące polecenia wbudowane w powłokę są dziedziczone z powłoki Bourne'a. Te polecenia są implementowane zgodnie ze standardem POSIX.
...
cd
cd [-L|[-P [-e]]] [directory]
Podejrzewam, że można pomyśleć o architekturze, w której cd
nie musi być wbudowany. Musisz jednak zobaczyć, co oznacza wbudowany. Jeśli napiszesz specjalny kod w powłoce, aby zrobić coś dla jakiegoś polecenia, zbliżasz się do wbudowania. Im więcej robisz, tym lepiej jest mieć wbudowaną funkcję.
Na przykład, możesz mieć powłokę z IPC do komunikowania się z podprocesami, i byłoby cd
program, który sprawdzałby istnienie katalogu i czy masz uprawnienia dostępu i to, a następnie komunikowałby się z powłoką, aby nakazał jej zmianę informator. Będziesz jednak musiał sprawdzić, czy proces komunikowania się z tobą jest dzieckiem (lub zastosuj specjalne środki komunikacji tylko z dziećmi, takie jak specjalny deskryptor pliku, pamięć współdzielona itp.) I czy proces jest w rzeczywistości uruchamianie zaufanego cd
programu lub czegoś innego. To cała puszka robaków.
Lub możesz mieć cd
program, który wywołuje chdir
system, i uruchamia nową powłokę ze wszystkimi bieżącymi zmiennymi środowiskowymi zastosowanymi do nowej powłoki, a następnie zabija swoją powłokę macierzystą (jakoś) po zakończeniu.1
Co gorsza, możesz nawet mieć system, w którym proces może zmieniać środowiska innych procesów (myślę, że technicznie można to zrobić za pomocą debuggerów). Taki system byłby jednak bardzo, bardzo wrażliwy.
Przekonasz się, że dodajesz coraz więcej kodu, aby zabezpieczyć takie metody, i znacznie łatwiej jest po prostu zrobić to wbudowanym.
To, że coś jest plikiem wykonywalnym, nie uniemożliwia jego wbudowania. Przykładem:
echo
i test
echo
i test
są narzędziami wymaganymi przez POSIX ( /bin/echo
i /bin/test
). Jednak prawie każda popularna powłoka ma wbudowane echo
i test
. Podobnie kill
jest również wbudowany, który jest dostępny jako program. Inne obejmują:
sleep
(nie tak często)
time
false
true
printf
Są jednak przypadki, w których polecenie nie może być niczym innym jak wbudowanym. Jednym z nich jest cd
. Zazwyczaj, jeśli pełna ścieżka nie jest określona, a nazwa polecenia odpowiada nazwie wbudowanego, wywoływana jest funkcja dostosowana do tego polecenia. W zależności od powłoki zachowanie wbudowanego i pliku wykonywalnego może się różnić (jest to szczególnie problemecho
, ponieważ ma on bardzo różne zachowania . Jeśli chcesz być pewien zachowania, lepiej jest wywołać plik wykonywalny przy użyciu pełną ścieżkę i ustaw zmienne takie jakPOSIXLY_CORRECT
(nawet wtedy nie ma prawdziwej gwarancji).
Technicznie nic nie stoi na przeszkodzie, aby zapewnić system operacyjny, który jest również powłoką i ma wszystkie polecenia jako wbudowane. Blisko tego skrajnego końca jest monolityczny BusyBox . BusyBox to pojedynczy plik binarny, który (w zależności od nazwy, z którą jest wywoływany) może zachowywać się jak dowolny z ponad 240 programów , w tym Almquist Shell ( ash
). Jeśli rozłączysz się PATH
podczas uruchamiania BusyBox ash
, programy dostępne w BusyBox są nadal dostępne bez określania PATH
. Zbliżają się do wbudowania powłoki, z wyjątkiem tego, że sama powłoka jest rodzajem wbudowania w BusyBox.
Jeśli spojrzysz na dash
źródło, wątek wykonania jest mniej więcej taki (oczywiście z dodatkowymi funkcjami związanymi z użyciem potoków i innych rzeczy):
main
→ cmdloop
→ evaltree
→evalcommand
evalcommand
następnie używa findcommand
do ustalenia, czym jest polecenie. Jeśli jest wbudowany, to :
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.cmd
jest struct
( struct builtincmd
), którego jednym z członków jest wskaźnik funkcji, z podpisem typowy main
: (int, char **)
. Te evalbltin
wywołania funkcji (w zależności od tego, czy wbudowany jest eval
komenda lub nie) albo evalcmd
, czy funkcja ta wskazówka. Rzeczywiste funkcje są zdefiniowane w różnych plikach źródłowych. echo
, na przykład jest :
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;
}
Wszystkie łącza do kodu źródłowego w tej sekcji są oparte na numerach wierszy, więc mogą ulec zmianie bez powiadomienia.
1 Systemy POSIX mają cd
plik wykonywalny .
Dygresja:
Istnieje wiele doskonałych postów w systemach Unix i Linux, które dotyczą zachowania powłoki. W szczególności:
Jeśli do tej pory nie zauważyłeś wzoru, prawie wszystkie z nich dotyczą Stéphane Chazelas .
type
polecenia