Dlaczego dane wyjściowe niektórych programów systemu Linux nie są wysyłane do STDOUT ani STDERR?
Właściwie chcę wiedzieć, jak niezawodnie przechwytywać wszystkie dane wyjściowe programu, bez względu na to, jakiego „strumienia” używa. Problemem jest to, że niektóre programy nie pozwalają na przechwycenie ich wyników.
Przykładem jest polecenie „czas”:
time sleep 1 2>&1 > /dev/null
real 0m1.003s
user 0m0.000s
sys 0m0.000s
lub
time sleep 1 &> /dev/null
real 0m1.003s
user 0m0.000s
sys 0m0.000s
Dlaczego widzę dane wyjściowe za każdym razem? Spodziewałem się, że wszystko to zostanie przekazane do / dev / null .
Jakiego strumienia wyjściowego używa czas i jak mogę go potokować do pliku?
Jednym ze sposobów obejścia tego problemu jest utworzenie skryptu Bash , na przykład combine.sh
zawierającego to polecenie:
$@ 2>&1
Następnie wynik „czasu” można zarejestrować w prawidłowy sposób:
combine.sh time sleep 1 &> /dev/null
(nie widać danych wyjściowych - poprawnie)
Czy istnieje sposób na osiągnięcie tego, co chcę bez użycia osobnego skryptu łączenia?
2>&1 > /dev/null
środki „2 teraz idzie gdzie 1 idzie (czyli terminal domyślnie), a następnie 1 teraz jedzie do / dev / null (ale 2 wciąż idzie do zacisku!) używać.>/dev/null 2>&1
powiedzieć „1 idzie teraz do / dev / null, a następnie 2 idzie tam, gdzie 1 idzie (tj. Również do / dev / null). To nadal nie działa tutaj, ponieważ wbudowany „czas” nie zostanie przekierowany, ale ogólnie jest poprawny (na przykład działałoby, jeśli użyjesz / usr / bin / time). Pomyśl o „2> & 1” jako kierunek kopiowania „na” 1 za 2, a nie 2 zamiar 1Odpowiedzi:
To pytanie zostało rozwiązane w BashFAQ / 032 . W twoim przykładzie:
Powód dlaczego
nie zachowuje się tak, jak się spodziewasz, ponieważ dzięki tej składni będziesz chciał
time
poleceniasleep 1 2>/dev/null
(tak, poleceniesleep 1
z przekierowaniem do stderr/dev/null
). Wbudowanetime
działa w ten sposób, aby to faktycznie było możliwe.bash
Wbudowane w rzeczywistości może to zrobić, ponieważ ... dobrze, to wbudowane. Takie zachowanie byłoby niemożliwe w przypadkutime
zwykle umieszczonego polecenia zewnętrznego/usr/bin
. W rzeczy samej:Teraz odpowiedź na twoje pytanie
jest: tak, wyjście przechodzi do stdout lub stderr .
Mam nadzieję że to pomoże!
źródło
exec 3>/some/file ; ls >&3 ;
)coproc
wbudowanym. Ale nie jest tak w przypadkutime
wbudowanego.Odpowiedzi na twoje szczególne pytanie dotyczące
time
wbudowanego, ale są pewne polecenia, które nie piszą ani do,stdout
ani dostderr
. Klasycznym przykładem jest polecenie Unixcrypt
.crypt
bez argumentów szyfruje standardowe wejściestdin
i zapisuje je na standardowe wyjściestdout
. Monituje użytkownika o podanie hasłagetpass()
, które domyślnie wyświetla monit o hasło/dev/tty
./dev/tty
jest bieżącym urządzeniem końcowym. Zapisywanie do/dev/tty
powoduje zapisywanie do bieżącego terminala (jeśli taki istnieje, patrzisatty()
).Powodem, dla
crypt
którego nie można pisać,stdout
jest to, że zapisuje zaszyfrowane dane wyjściowestdout
. Ponadto lepiej jest pytać/dev/tty
zamiast pisać, abystderr
użytkownik przekierowałstdout
istderr
monit nadal był widoczny. (Z tego samego powoducrypt
nie można odczytać hasłastdin
, ponieważ jest ono używane do odczytu danych do zaszyfrowania).źródło
time sleep 1 > /dev/null 2>&1
# przekierowuje wyjście „sleep” do null. Następnie „czas” zapisuje własne wyjście, bez przekierowań. To jest jak „time (sleep 1 > /dev/null 2>&1)
”.(time sleep 1) > /dev/null 2>&1
# uruchamia „czas uśpienia 1”, a następnie przekierowuje dane wyjściowe na zero.[] s
źródło
Problem w twoim przypadku polega na tym, że przekierowanie działa w inny sposób. Napisałeś
To przekierowuje standardowe wyjście,
/dev/null
a następnie przekierowuje standardowy błąd na standardowe wyjście.Aby przekierować wszystkie dane wyjściowe, musisz napisać
Następnie błąd standardowy zostanie przekierowany na standardowe wyjście, a następnie wszystkie standardowe wyjście (zawierające błąd standardowy) zostanie przekierowane na
/dev/null
.źródło
time
. Zobacz moją odpowiedź na kilka wyjaśnień.