Zwykle $0
w skrypcie ustawiana jest nazwa skryptu lub cokolwiek, co zostało wywołane jako (w tym ścieżka). Jeśli jednak używam bash
z tą -c
opcją, $0
jest ustawiony na pierwszy z argumentów przekazanych po ciągu polecenia:
bash -c 'echo $0 ' foo bar
# foo
W efekcie wydaje się, że parametry pozycyjne zostały przesunięte, ale obejmują $0
. Jednak shift
w ciągu polecenia nie ma wpływu $0
(jak zwykle):
bash -c 'echo $0; shift; echo $0 ' foo bar
# foo
# foo
Dlaczego to pozornie dziwne zachowanie ciągów poleceń? Zauważ, że szukam powodu, uzasadnienia, za wdrożeniem tak dziwnego zachowania.
Można spekulować, że taki ciąg komend nie wymagałby $0
parametru jak zwykle zdefiniowano, więc dla oszczędności jest on również używany do zwykłych argumentów. Jednak w takim przypadku zachowanie shift
jest dziwne. Inną możliwością jest $0
zdefiniowanie zachowania programów (la bash
nazywane jako sh
lub vim
nazywane as vi
), ale nie może tak być, ponieważ $0
tutaj jest widoczne tylko w ciągu poleceń, a nie przez programy w nim wywołane. Nie mogę wymyślić żadnego innego zastosowania $0
, więc nie mogę tego wyjaśnić.
-
dla$0
argumentu jako idiomu, jak wsh -c 'foo $1 $2' - a b
. W ten sposób wygląda to całkiem normalnie (gdy się dowiesz, co to-
znaczy)echo 'echo the other side of this pipe globs "$@"' | sh -s -- *
, niestety,$0
generalnie nie być ustawialnym parametrem z-s
opcją tream ... Można go jednak używać na wiele takich samych sposobówxargs
. I inne poza tym.--
, to mogłaby mieć zwykłą interpretację „stąd zaczynają się argumenty”, widzianą w niektórych innych programach. Z drugiej strony może to być mylące dla osób, które nie są zaznajomione z-c
myśleniem, że--
faktycznie mają taką interpretację.Odpowiedzi:
Daje to możliwość ustawienia / wyboru
$0
podczas korzystania ze skryptu wbudowanego. W przeciwnym razie$0
byłoby po prostubash
.Następnie możesz na przykład:
Nie wszystkie muszle to robiły. Powłoka Bourne'a tak zrobiła. Powłoka Korna (i Almquista) zdecydowała się na zamianę pierwszego parametru
$1
. POSIX ostatecznie poszedł na drodze Bourne, więcksh
iash
pochodne powrócił do tego później (więcej o tym w http://www.in-ulm.de/~mascheck/various/find/#shell ). Oznaczało to, że przez długi czassh
(w zależności od systemu opartego na powłoce Bourne'a, Almquista lub Korna) nie wiedziałeś, czy poszedł pierwszy argument,$0
czy też$1
, dla przenośności, musiałeś robić takie rzeczy jak:Lub:
Na szczęście POSIX określił nowe zachowanie tam, gdzie pojawia się pierwszy argument
$0
, dzięki czemu możemy teraz przenośnie wykonać:źródło
bash -c 'echo txt files are "$@"' meaningful-arg0-for-error *.txt
na Ubuntu 14.04, bashversion 4.3.11(1)-release
i mam:txt files are *.txt
. Ootxt
plików w bieżącym katalogu). Zobacz takżebash -c 'echo "${1?}"' foo
sh -c 'shift "$2"; echo txt files are "$@"' tentative-arg0 3 2 *.txt
jest fantastycznie pomysłowy!SHELL -c 'shift $1; command' 2 1 arg1 arg2 ...
haha ...To zachowanie jest zdefiniowane przez POSIX :
Co do tego, dlaczego chcesz tego zachowania: to wygładza lukę między skryptem a
-c
łańcuchem. Możesz bezpośrednio konwertować między nimi bez zmiany zachowania. Inne obszary opierają się na tym, że są identyczne.Jest to również zgodne z ogólnym działaniem argumentów programu: ostatecznie sprowadza się to do wywołania jednego z
exec
funkcji, w której znajduje się również pierwszy podany argument$0
, i równie często ten argument jest taki sam, jak uruchamiany plik wykonywalny. Czasami jednak potrzebujesz specjalnej wartości i nie byłoby innego sposobu, aby ją zdobyć. Biorąc pod uwagę, że argument istnieje, musi zostać odwzorowany na coś, a użytkownik musi mieć możliwość ustawienia tego, co to jest.Ta konsekwencja (i prawdopodobnie historyczny wypadek) prowadzi do sytuacji, którą znajdziesz.
źródło
argv[0]
.$0
jest ustawiony naargv[0]
przekazywany tylkoexecve()
wtedy, gdy jest podobnysh
lubbash
. W przypadku skryptów$0
jest ustawiony na ścieżkę podaną jako argument 1, 2 ... do interpretera (w przypadku skryptów wykonywanych bezpośrednio, która pochodzi z pierwszego argumentu ścieżki do execve ()).