To bardzo ręczny wątek, dzięki. Klasa do uruchamiania poleceń i uzyskiwania informacji zwrotnych jest świetna w przykładowym kodzie.
pokaż
3
Dla przyszłych pracowników Google. Jeśli chcesz dowiedzieć się o innych wywołaniach poleceń systemowych i ich różnicach, zapoznaj się z odpowiedzią SO .
Jeśli otoczysz swoje polecenie backtickami, to wcale nie musisz (jawnie) wywoływać system (). Backticks wykonują polecenie i zwracają dane wyjściowe jako ciąg. Następnie możesz przypisać wartość do zmiennej takiej jak:
co jeśli muszę podać zmienną jako część mojego polecenia? Oznacza to, co przełożyłoby się na coś takiego jak system („ls” + nazwa pliku), kiedy mają być używane backtyki?
Vijay Dev
47
Można to zrobić ocenę ekspresji tak samo jak regularne ciągi: ls #{filename}.
Craig Walker,
36
Ta odpowiedź nie jest wskazana: wprowadza nowy problem niezamierzonego wprowadzania danych przez użytkownika.
Dogweather
4
@Dogweather: to może być prawda, ale czy różni się ona od innych metod?
Craig Walker
20
jeśli chcesz przechwycić stderr, po prostu umieść 2> i 1 na końcu swojej komendy. np. wyjście =command 2>&1
micred
243
Należy pamiętać, że wszystkie rozwiązania, gdzie przechodzą ciąg zawierający warunkiem użytkownika wartości system, %x[]itp są niebezpieczne! Niebezpieczne oznacza w rzeczywistości: użytkownik może uruchomić kod w celu uruchomienia w kontekście i przy wszystkich uprawnieniach programu.
O ile mogę tylko powiedzieć systemi Open3.popen3zapewniam bezpieczny / uciekający wariant w Ruby 1.8. W Ruby 1.9 IO::popenakceptuje również tablicę.
Po prostu przekaż każdą opcję i argument jako tablicę do jednego z tych wywołań.
Jeśli potrzebujesz nie tylko statusu wyjścia, ale także wyniku, którego prawdopodobnie chcesz użyć Open3.popen3:
Jest to jedyna odpowiedź, która faktycznie odpowiada na pytanie i rozwiązuje problem bez wprowadzania nowych (niezamówione dane wejściowe).
Dogweather
2
Dzięki! Jest to odpowiedź, na którą liczyłem. Jedna korekta: getswywołania powinny przekazać argument nil, ponieważ w przeciwnym razie otrzymamy pierwszy wiersz wyniku. Więc np stdout.gets(nil).
Czy ktoś wie, czy coś się zmieniło w Ruby 2.0 lub 2.1? Będziemy wdzięczni za zmiany lub komentarze ;-)
Simon Hürlimann
1
Myślę, że w dyskusji Open3.popen3brakuje poważnego problemu: jeśli masz podproces, który zapisuje na standardowe wyjście więcej danych niż jest w stanie pomieścić potok, podproces zostaje zawieszony stderr.write, a twój program utknie stdout.gets(nil).
hagello
165
Dla przypomnienia, jeśli chcesz zarówno (wynik i wynik operacji) możesz:
To tylko przechwytuje stdout, a stderr idzie do konsoli. Aby uzyskać stderr, użyj: output=`ls no_existing_file 2>&1`; result=$?.success?
peterept
8
Ta odpowiedź jest niebezpieczna i nie należy jej używać - jeśli polecenie nie jest stałe, wówczas składnia cofnięcia może spowodować błąd, prawdopodobnie lukę w zabezpieczeniach. (I nawet jeśli jest to stała, prawdopodobnie spowoduje to, że ktoś użyje jej do niestałości później i spowoduje błąd). Zobacz poprawne rozwiązanie Simona Hürlimanna .
Greg Price
23
Wyrazy uznania dla Grega Price za zrozumienie potrzeby ucieczki od danych wejściowych od użytkownika, ale twierdzenie, że ta odpowiedź w formie pisemnej jest niebezpieczne, jest niewłaściwe. Wspomniana metoda Open3 jest bardziej skomplikowana i wprowadza więcej zależności, a argumentem, że ktoś „użyje jej do niestałości później” jest słaby. To prawda, że prawdopodobnie nie użyłbyś ich w aplikacji Railsowej, ale w przypadku prostego skryptu narzędzia systemowego bez możliwości niezaufanego wprowadzania danych przez użytkownika backticks są w porządku i nikt nie powinien czuć się źle z ich użyciem.
Używanie odwrotności ruby i jej %xaliasu NIE JEST BEZPIECZNE W ŻADNYM OKOLICY, jeśli zostanie użyte z niezaufanymi danymi. Jest NIEBEZPIECZNY , prosty i prosty:
untrusted ="; date; echo"
out =`echo #{untrusted}`# BAD
untrusted ='"; date; echo"'
out =`echo "#{untrusted}"`# BAD
untrusted ="'; date; echo'"
out =`echo '#{untrusted}'`# BAD
Z kolei systemfunkcja poprawnie unika argumentów, jeśli jest używana poprawnie :
ret = system "echo #{untrusted}"# BAD
ret = system 'echo', untrusted # good
Problem w tym, że zwraca kod wyjścia zamiast wyniku, a przechwycenie tego ostatniego jest skomplikowane i nieuporządkowane.
Najlepsza odpowiedź w tym wątku jak dotąd wspomina o Open3, ale nie o funkcjach, które najlepiej pasują do tego zadania. Open3.capture2, capture2eA capture3praca jak system, ale powróci dwa lub trzy argumenty:
out, err, st =Open3.capture3("echo #{untrusted}")# BAD
out, err, st =Open3.capture3('echo', untrusted)# good
out_err, st =Open3.capture2e('echo', untrusted)# good
out, st =Open3.capture2('echo', untrusted)# good
p st.exitstatus
Kolejne wspomnienia IO.popen(). Składnia może być niezdarna w tym sensie, że chce tablicy jako danych wejściowych, ale działa również:
out = IO.popen(['echo', untrusted]).read # good
Dla wygody możesz zawinąć Open3.capture3()funkcję, np .:
## Returns stdout on success, false on failure, nil on error#def syscall(*cmd)begin
stdout, stderr, status =Open3.capture3(*cmd)
status.success?&& stdout.slice!(0..-(1+ $/.size))# strip trailing eolrescueendend
Przykład:
p system('foo')
p syscall('foo')
p system('which','foo')
p syscall('which','foo')
p system('which','which')
p syscall('which','which')
Daje następujące:
nilnilfalsefalse/usr/bin/which <— stdout from system('which','which')true<- p system('which','which')"/usr/bin/which"<- p syscall('which','which')
To jest poprawna odpowiedź. Jest również najbardziej pouczający. Brakuje tylko ostrzeżenia o zamknięciu standardowych plików. Zobacz ten inny komentarz : require 'open3'; output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read } Zauważ, że forma bloku automatycznie zamyka stdin, stdout i stderr - w przeciwnym razie musiałyby zostać jawnie zamknięte .
Peter H. Boling
@ PeterH. Boling: Najlepsze, co wiem capture2, capture2eicapture3 także automatycznie zamknij je std * s. (Przynajmniej nigdy nie spotkałem się z tym problemem).
Denis de Bernardy
bez użycia formularza blokowego nie ma sposobu, aby baza kodów wiedziała, kiedy coś powinno zostać zamknięte, więc bardzo wątpię, aby zostały zamknięte. Prawdopodobnie nigdy nie natknąłeś się na problem, ponieważ nie zamknięcie go nie spowoduje problemów w krótkotrwałym procesie, a jeśli wystarczająco często restartujesz długotrwały proces, otto też się tam nie pojawi, chyba że otwierasz std * s w pętla. Linux ma wysoki limit deskryptorów plików, do którego można trafić, ale dopóki go nie osiągniesz, nie zobaczysz „błędu”.
@Dennis de Barnardy Być może nie zauważyłeś, że podłączyłem tę samą dokumentację klasową (chociaż dla Ruby 2.0.0 i inną metodę. Ruby-doc.org/stdlib-2.1.1/libdoc/open3/rdoc/… Z przykładu : `` `stdin, stdout, stderr, wait_thr = Open3.popen3 ([env,] cmd ... [, opts]) pid = wait_thr [: pid] # pid rozpoczętego procesu ... stdin.close # stdin , stdout i stderr powinny być jawnie zamknięte w tej formie. stdout.close stderr.close `` Właśnie cytowałem dokumentację. "# stdin, stdout i stderr powinny być jawnie zamknięte w tej formie."
Peter H. Boling
61
Możesz użyć system () lub% x [] w zależności od tego, jaki wynik potrzebujesz.
system () zwraca true, jeśli polecenie zostało znalezione i uruchomione pomyślnie, w przeciwnym razie false.
>> s = system 'uptime'10:56 up 3 days,23:10,2 users, load averages:0.170.170.14=>true>> s.class=>TrueClass>> $?.class=>Process::Status
Z drugiej strony% x [..] zapisuje wyniki polecenia jako ciąg znaków:
>> result =%x[uptime]=>"13:16 up 4 days, 1:30, 2 users, load averages: 0.39 0.29 0.23\n">> p result
"13:16 up 4 days, 1:30, 2 users, load averages: 0.39 0.29 0.23\n">> result.class=>String
W blogu Jaya Fieldsa szczegółowo wyjaśniono różnice między używaniem systemu, exec i% x [..].
Dziękujemy za wskazówkę dotyczącą używania% x []. Właśnie rozwiązałem problem, w którym użyłem tylnych znaczników w skrypcie ruby w Mac OS X. Podczas uruchamiania tego samego skryptu na komputerze z systemem Windows z Cygwin, nie powiodło się z powodu tylnych znaczników, ale działało z% x [].
Henrik Warne,
22
Jeśli chcesz uniknąć argumentów, w Ruby 1.9 IO.popen akceptuje również tablicę:
p IO.popen(["echo","it's escaped"]).read
We wcześniejszych wersjach można używać Open3.popen3 :
require "open3"Open3.popen3("echo","it's escaped"){|i, o| p o.read }
Jeśli musisz również przekazać standardowe wejście, powinno to działać zarówno w wersji 1.9, jak i 1.8:
out = IO.popen("xxd -p","r+"){|io|
io.print "xyz"
io.close_write
io.read.chomp
}
p out # "78797a"
Wsteczne nie wytwarzają danych wyjściowych na terminalu.
Mei
3
Nie wytwarza stderr, ale daje stdout.
Nickolay Kondratenko
1
Nie pisze do stdout ani stderr. Spróbujmy tego przykładu ruby -e '%x{ls}'- uwaga, brak danych wyjściowych. (fyi %x{}jest równoważne z
atakami wstecznymi
To działało świetnie. Użycie shspowoduje echo wyjścia do konsoli (tj. STDOUT), a także zwróci go. To nie
Joshua Pinter
19
Innym sposobem jest:
f = open("|ls")
foo = f.read()
Zauważ, że to znak „potoku” przed „ls” w otwartym. Można to również wykorzystać do wprowadzenia danych do standardowego wejścia programów, jak również do odczytu standardowego wyjścia.
Podczas gdy używanie backticks lub popen jest często tym, czego naprawdę chcesz, tak naprawdę nie odpowiada na zadane pytanie. Mogą istnieć ważne powody przechwytywania systemdanych wyjściowych (być może w przypadku testów automatycznych). Trochę Googlinga znalazło odpowiedź, o której pomyślałem, że opublikuję tutaj z korzyścią dla innych.
Ponieważ potrzebowałem tego do testowania, mój przykład wykorzystuje konfigurację bloku do przechwycenia standardowego wyjścia, ponieważ rzeczywiste systemwywołanie jest zakopane w testowanym kodzie:
W przypadku długo działającego polecenia spowoduje to zapisanie danych wyjściowych w czasie rzeczywistym. Możesz również przechowywać dane wyjściowe za pomocą IO.pipe i przekierować je z systemu jądra #.
Odpowiedzi:
Chciałbym trochę rozszerzyć i wyjaśnić odpowiedź na chaos .
Jeśli otoczysz swoje polecenie backtickami, to wcale nie musisz (jawnie) wywoływać system (). Backticks wykonują polecenie i zwracają dane wyjściowe jako ciąg. Następnie możesz przypisać wartość do zmiennej takiej jak:
lub
źródło
ls #{filename}
.command 2>&1
Należy pamiętać, że wszystkie rozwiązania, gdzie przechodzą ciąg zawierający warunkiem użytkownika wartości
system
,%x[]
itp są niebezpieczne! Niebezpieczne oznacza w rzeczywistości: użytkownik może uruchomić kod w celu uruchomienia w kontekście i przy wszystkich uprawnieniach programu.O ile mogę tylko powiedzieć
system
iOpen3.popen3
zapewniam bezpieczny / uciekający wariant w Ruby 1.8. W Ruby 1.9IO::popen
akceptuje również tablicę.Po prostu przekaż każdą opcję i argument jako tablicę do jednego z tych wywołań.
Jeśli potrzebujesz nie tylko statusu wyjścia, ale także wyniku, którego prawdopodobnie chcesz użyć
Open3.popen3
:Zauważ, że forma bloku automatycznie zamknie stdin, stdout i stderr - w przeciwnym razie będą musiały zostać jawnie zamknięte .
Więcej informacji tutaj: Tworzenie poleceń powłoki sanitarnej lub wywołań systemowych w Ruby
źródło
gets
wywołania powinny przekazać argumentnil
, ponieważ w przeciwnym razie otrzymamy pierwszy wiersz wyniku. Więc npstdout.gets(nil)
.Open3.popen3
brakuje poważnego problemu: jeśli masz podproces, który zapisuje na standardowe wyjście więcej danych niż jest w stanie pomieścić potok, podproces zostaje zawieszonystderr.write
, a twój program utkniestdout.gets(nil)
.Dla przypomnienia, jeśli chcesz zarówno (wynik i wynik operacji) możesz:
źródło
output=`ls no_existing_file 2>&1`; result=$?.success?
Prosta droga to zrobić prawidłowo i bezpiecznie jest w użyciu
Open3.capture2()
,Open3.capture2e()
lubOpen3.capture3()
.Używanie odwrotności ruby i jej
%x
aliasu NIE JEST BEZPIECZNE W ŻADNYM OKOLICY, jeśli zostanie użyte z niezaufanymi danymi. Jest NIEBEZPIECZNY , prosty i prosty:Z kolei
system
funkcja poprawnie unika argumentów, jeśli jest używana poprawnie :Problem w tym, że zwraca kod wyjścia zamiast wyniku, a przechwycenie tego ostatniego jest skomplikowane i nieuporządkowane.
Najlepsza odpowiedź w tym wątku jak dotąd wspomina o Open3, ale nie o funkcjach, które najlepiej pasują do tego zadania.
Open3.capture2
,capture2e
Acapture3
praca jaksystem
, ale powróci dwa lub trzy argumenty:Kolejne wspomnienia
IO.popen()
. Składnia może być niezdarna w tym sensie, że chce tablicy jako danych wejściowych, ale działa również:Dla wygody możesz zawinąć
Open3.capture3()
funkcję, np .:Przykład:
Daje następujące:
źródło
require 'open3'; output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read }
Zauważ, że forma bloku automatycznie zamyka stdin, stdout i stderr - w przeciwnym razie musiałyby zostać jawnie zamknięte .capture2
,capture2e
icapture3
także automatycznie zamknij je std * s. (Przynajmniej nigdy nie spotkałem się z tym problemem).Open3#popen2
,popen2e
ipopen3
z góry określonego bloku: ruby-doc.org/stdlib-2.1.1/libdoc/open3/rdoc/...Możesz użyć system () lub% x [] w zależności od tego, jaki wynik potrzebujesz.
system () zwraca true, jeśli polecenie zostało znalezione i uruchomione pomyślnie, w przeciwnym razie false.
Z drugiej strony% x [..] zapisuje wyniki polecenia jako ciąg znaków:
W blogu Jaya Fieldsa szczegółowo wyjaśniono różnice między używaniem systemu, exec i% x [..].
źródło
Jeśli chcesz uniknąć argumentów, w Ruby 1.9 IO.popen akceptuje również tablicę:
We wcześniejszych wersjach można używać Open3.popen3 :
Jeśli musisz również przekazać standardowe wejście, powinno to działać zarówno w wersji 1.9, jak i 1.8:
źródło
Używasz backticksa:
źródło
ruby -e '%x{ls}'
- uwaga, brak danych wyjściowych. (fyi%x{}
jest równoważne zsh
spowoduje echo wyjścia do konsoli (tj. STDOUT), a także zwróci go. To nieInnym sposobem jest:
Zauważ, że to znak „potoku” przed „ls” w otwartym. Można to również wykorzystać do wprowadzenia danych do standardowego wejścia programów, jak również do odczytu standardowego wyjścia.
źródło
Stwierdziłem, że poniższe informacje są przydatne, jeśli potrzebujesz wartości zwracanej:
W szczególności chciałem wyświetlić listę wszystkich procesów Java na moim komputerze i użyłem tego:
źródło
Jak już wyjaśnił Simon Hürlimann , Open3 jest bezpieczniejszy niż backticks itp.
Zauważ, że forma bloku automatycznie zamknie stdin, stdout i stderr - w przeciwnym razie będą musiały zostać jawnie zamknięte .
źródło
Podczas gdy używanie backticks lub popen jest często tym, czego naprawdę chcesz, tak naprawdę nie odpowiada na zadane pytanie. Mogą istnieć ważne powody przechwytywania
system
danych wyjściowych (być może w przypadku testów automatycznych). Trochę Googlinga znalazło odpowiedź, o której pomyślałem, że opublikuję tutaj z korzyścią dla innych.Ponieważ potrzebowałem tego do testowania, mój przykład wykorzystuje konfigurację bloku do przechwycenia standardowego wyjścia, ponieważ rzeczywiste
system
wywołanie jest zakopane w testowanym kodzie:Ta metoda przechwytuje dane wyjściowe w danym bloku przy użyciu pliku tymczasowego do przechowywania rzeczywistych danych. Przykładowe użycie:
Możesz zastąpić
system
rozmowę dowolnym połączeniem wewnętrznymsystem
. Możesz także użyć podobnej metody przechwytywania,stderr
jeśli chcesz.źródło
Jeśli chcesz przekierować dane wyjściowe do pliku
Kernel#system
, możesz zmodyfikować deskryptory w następujący sposób:przekieruj stdout i stderr do pliku (/ tmp / log) w trybie dołączania:
system('ls -al', :out => ['/tmp/log', 'a'], :err => ['/tmp/log', 'a'])
W przypadku długo działającego polecenia spowoduje to zapisanie danych wyjściowych w czasie rzeczywistym. Możesz również przechowywać dane wyjściowe za pomocą IO.pipe i przekierować je z systemu jądra #.
źródło
Jako bezpośrednią wymianę systemu (...) możesz użyć Open3.popen3 (...)
Dalsza dyskusja: http://tech.natemurray.com/2007/03/ruby-shell-commands.html
źródło
Nie znalazłem tego tutaj, więc dodając go, miałem problemy z uzyskaniem pełnej wydajności.
źródło: http://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html
źródło
źródło