Powiedz, czy napisałem program z następującym wierszem:
int main(int argc, char** argv)
Teraz wie, jakie argumenty wiersza poleceń są mu przekazywane, sprawdzając treść argv
.
Czy program może wykryć, ile spacji między argumentami? Na przykład, gdy wpisuję je w bash:
ibug@linux:~ $ ./myprog aaa bbb
ibug@linux:~ $ ./myprog aaa bbb
Środowisko to nowoczesny Linux (jak Ubuntu 16.04), ale przypuszczam, że odpowiedź powinna dotyczyć każdego systemu zgodnego z POSIX.
Odpowiedzi:
Nie ma sensu mówić o „odstępach między argumentami”; to jest koncepcja powłoki.
Zadaniem powłoki jest przyjmowanie całych linii danych wejściowych i formowanie ich w tablice argumentów do uruchamiania poleceń. Może to obejmować parsowanie ciągów cytowanych, rozwijanie zmiennych, symboli wieloznacznych plików i wyrażeń tyldy i więcej. Polecenie jest uruchamiane za pomocą standardowego
exec
wywołania systemowego, które akceptuje wektor ciągów znaków.Istnieją inne sposoby tworzenia wektora ciągów. Wiele programów rozwidla i wykonuje własne podprocesy za pomocą wcześniej określonych wywołań poleceń - w takim przypadku nigdy nie ma czegoś takiego jak „linia poleceń”. Podobnie, powłoka graficzna (na pulpicie) może rozpocząć proces, gdy użytkownik przeciągnie ikonę pliku i upuści ją w widżecie poleceń - ponownie nie ma linii tekstowej, w której znaki powinny znajdować się między argumentami.
Jeśli chodzi o wywołane polecenie, to, co dzieje się w powłoce lub innym procesie nadrzędnym / prekursorowym, jest prywatne i ukryte - widzimy tylko tablicę ciągów, które standard C określa, które
main()
mogą zaakceptować.źródło
tar cf texts.tar *.txt
program tar otrzymuje dwa argumenty i musi rozszerzyć sam drugi (*.txt
). Wiele osób nie zdaje sobie sprawy, jak to naprawdę działa, dopóki nie zaczną pisać własnych skryptów / programów obsługujących argumenty.Ogólnie nie. Analiza wiersza poleceń jest wykonywana przez powłokę, która nie udostępnia nie analizowanego wiersza dla wywoływanego programu. W rzeczywistości twój program może być wykonany z innego programu, który utworzył argv nie przez parsowanie łańcucha, ale przez programową tablicę argumentów.
źródło
execve(2)
.Nie, nie jest to możliwe, chyba że spacje są częścią argumentu.
Polecenie uzyskuje dostęp do poszczególnych argumentów z tablicy (w takiej lub innej formie, w zależności od języka programowania), a rzeczywisty wiersz poleceń może zostać zapisany w pliku historii (jeśli zostanie wpisany w interaktywnym wierszu poleceń w powłoce zawierającej pliki historii), ale jest nigdy nie przekazano polecenia w żadnej formie.
Wszystkie polecenia w Uniksie są w końcu wykonywane przez jedną z
exec()
rodziny funkcji. Pobierają one nazwę polecenia oraz listę lub tablicę argumentów. Żadna z nich nie przyjmuje wiersza poleceń, który został wpisany w wierszu poleceń powłoki.system()
Funkcja robi, ale jego ciąg argumentu później wykonywane przezexecve()
, co znowu bierze tablicę argumentów zamiast ciąg wiersza poleceń.źródło
hello
iworld
to dosłownie spacje między dwoma argumentami.hello
iworld
jest dosłownie dostarczając drugi z trzech argumentów.Zasadniczo nie jest to możliwe, jak wyjaśniono kilka innych odpowiedzi.
Jednak powłoki uniksowe są zwykłymi programami (i interpretują wiersz poleceń i globują go, tzn. Rozszerzają polecenie przed wykonaniem
fork
&execve
dla niego). Zobacz to wyjaśnienie dotyczącebash
operacji powłoki . Możesz napisać własną powłokę (lub załatać istniejącą powłokę wolnego oprogramowania , np. GNU bash ) i użyć jej jako powłoki (lub nawet powłoki logowania, patrz passwd (5) i shells (5) ).Na przykład, możesz mieć swój własny program powłoki, który umieści pełny wiersz poleceń w jakiejś zmiennej środowiskowej (wyobraź sobie
MY_COMMAND_LINE
na przykład) - lub użyj innego rodzaju komunikacji międzyprocesowej w celu przesłania wiersza poleceń z powłoki do procesu potomnego.Nie rozumiem, dlaczego chcesz to zrobić, ale możesz kodować powłokę zachowującą się w taki sposób (ale ja tego nie zalecam).
BTW, program może zostać uruchomiony przez jakiś program, który nie jest powłoką (ale który wykonuje fork (2), a następnie wykonuje (2) lub po prostu
execve
uruchamia program w bieżącym procesie). W takim przypadku w ogóle nie ma wiersza polecenia, a program można uruchomić bez polecenia ...Zauważ, że możesz mieć jakiś (specjalistyczny) system Linux bez zainstalowanej powłoki. To dziwne i niezwykłe, ale możliwe. Będziesz wtedy trzeba napisać specjalizuje startowy programu począwszy innych programów w miarę potrzeb - bez użycia jakichkolwiek skorupę ale wykonując
fork
&execve
wywołań systemowych.Przeczytaj także Systemy operacyjne: trzy proste elementy i nie zapominaj, że
execve
praktycznie zawsze jest to wywołanie systemowe (w Linuksie są wymienione w syscalls (2) , patrz także wprowadzenie (2) ), które ponownie inicjują wirtualną przestrzeń adresową (i niektóre inne rzeczy) procesu, który to robi.źródło
argv[0]
nazwa programu i pozostałe elementy argumentów są specyfikacjami POSIX i nie można ich zmienić.argv[-1]
Zakładam, że środowisko wykonawcze może określać dla wiersza poleceń, ...execve
dokumentację. Nie możesz używaćargv[-1]
, używanie jest niezdefiniowane.execvepluscmd
funkcję inną niż POSIX z dodatkowym parametrem (lub konwencją argv), syscall konstruuje wektor argumentu dla main, który zawiera wskaźnik do linii poleceń przed wskaźnikiem do nazwy programu, a następnie przekazuje adres wskaźnika do nazwy programu, jakargv
podczas wywoływania programumain
...sh
. Więc nie jest nowy.Zawsze możesz powiedzieć swojej powłoce, aby poinformowała aplikacje, jaki kod powłoki prowadzi do ich wykonania. Na przykład,
zsh
przekazując te informacje do$SHELL_CODE
zmiennej środowiskowej za pomocąpreexec()
haka (printenv
użytego jako przykład, którego użyłbyśgetenv("SHELL_CODE")
w swoim programie):Wszystkie te byłyby wykonywane
printenv
jako:Zezwolenie
printenv
na pobranie kodu zsh, który prowadzi do wykonaniaprintenv
tych argumentów. To, co chciałbyś zrobić z tymi informacjami, nie jest dla mnie jasne.Dzięki
bash
, funkcja najbliższa dozsh
'spreexec()
używałaby jej$BASH_COMMAND
wDEBUG
pułapce, ale zauważ, żebash
robi pewien poziom przepisywania w tym (a w szczególności refaktoryzuje niektóre białe spacje używane jako separator) i to jest stosowane do każdego polecenia (no, niektóre) uruchom, a nie całą linię poleceń wprowadzoną w wierszu poleceń (zobacz takżefunctrace
opcję).Zobacz, jak niektóre spacje, które są ogranicznikami w składni języka powłoki, zostały ściśnięte do 1 i jak nie pełna linia poleceń nie zawsze jest przekazywana do polecenia. Prawdopodobnie nie jest to przydatne w twoim przypadku.
Pamiętaj, że nie radziłbym robić tego rodzaju rzeczy, ponieważ potencjalnie wyciekasz poufne informacje do każdego polecenia, jak w:
wyciekłby ten sekret do obu
wc
iuntrustedcmd
.Oczywiście, możesz zrobić coś takiego dla innych języków niż shell. Na przykład w C można użyć makr eksportujących kod C, który wykonuje polecenie do środowiska:
Przykład:
Zobacz, jak niektóre miejsca zostały skondensowane przez preprocesor C, jak w przypadku bash. W większości, jeśli nie we wszystkich językach, ilość miejsca używanego w separatorach nie robi różnicy, więc nie jest zaskakujące, że kompilator / interpreter korzysta tutaj z pewnej swobody.
źródło
BASH_COMMAND
nie zawierałem oryginalnych argumentów oddzielających białe znaki, więc nie było to przydatne w przypadku dosłownego żądania OP. Czy ta odpowiedź zawiera jakąkolwiek demonstrację dla tego konkretnego przypadku użycia?Dodam tylko to, czego brakuje w pozostałych odpowiedziach.
Nie
Zobacz inne odpowiedzi
Może w pewnym sensie
W programie nie można nic zrobić, ale można uruchomić coś w powłoce po uruchomieniu programu.
Musisz użyć cudzysłowów. Więc zamiast
musisz zrobić jedną z nich
Spowoduje to przekazanie do programu pojedynczego argumentu ze wszystkimi spacjami. Istnieje różnica między nimi, druga jest dosłowna, dokładnie tak, jak się wydaje (oprócz tego, że
'
musi być wpisana jako\'
). Pierwszy interpretuje niektóre znaki, ale dzieli się na kilka argumentów. Aby uzyskać więcej informacji, zobacz cytowanie powłoki. Więc nie ma potrzeby przepisywania powłoki, projektanci powłok już o tym pomyśleli. Ponieważ jednak jest to teraz jeden argument, będziesz musiał wykonać więcej przekazywania w programie.Opcja 2
Przekaż dane przez stdin. Jest to normalny sposób na pobranie dużej ilości danych do polecenia. na przykład
lub
./myprog
Tell me what you want to tell me:
aaaa bbb
ctrl-d
(Kursywa jest wyjściem programu)
źródło
./myprog␣"␣␣␣␣␣aaa␣␣␣␣␣␣bbb"
Wykonuje (zwykle w procesie dziecko) pliku przechowywane./myprog
i przekazuje je dwa argumenty./myprog
i␣␣␣␣␣aaa␣␣␣␣␣␣bbb
(argv[0]
aargc[1]
,argc
wynosi 2), a także w OP przestrzeń, która oddziela te dwa argumenty nie są przekazywane w sposób domyprog
.