Два println
оператора обрабатываются двумя разными потоками. Результат снова зависит от того, в какой среде вы запускаете код. Например, я выполнил следующий код в IntelliJ и в командной строке по 5 раз.
public class Test {public static void main (String [] args) {for (int i = 0; i & lt; 10; i ++) {System.out.print ("OUT") ; System.err.print («ERR»); }}}
Это приводит к следующему выводу: Commandline
OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR OUT ERR
IntelliJ:
ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT ERR ERR ERR ERR ERR ERR ERR ERR ERR ERR
Я полагаю, что разные среды обрабатывают буфер иначе. Один из способов увидеть, что эти потоки обрабатываются различными потоками, - это добавить в цикл инструкцию sleep
. Вы можете попробовать изменить значение, которое вы установили для сна, и посмотреть, что это infact, обрабатываемые разными потоками.
public class Test {public static void main (String [] args) {for ( int i = 0; i & lt; 10; i ++) {System.out.print ("OUT"); System.err.print («ERR»); try {Thread.sleep (500); } catch (InterruptedException e) {e.printStackTrace (); }}}}
Выход в этом случае оказался
OUT ERR ERR OUT ERR OUT OUT ERR OUT ERR ERR OUT OUT ERR ERR OUT OUT ERR OUT ERR OUT ERR ERR OUT ERR OUT OUT ERR OUT ERR ERR OUT OUT ERR ERR OUT OUT ERR OUT ERR ERR OUT ERR OUT OUT ERR ERR OUT OUT ERR ERR OUT OUT ERR OUT ERR ERR OUT ERR OUT ERR OUT OUT ERR ERR OUT OUT ERR ERR OUT ERR OUT OUT ERR OUT ERR OUT OUT ERR OUT ERR OUT ERR ERR OUT OUT ERR ERR OUT OUT ERR ERR OUT ERR OUT OUT ERR OUT ERR
Один из способов заставить его для печати в том же порядке будет использоваться .flush ()
, который работал для меня. Но это не то, что не все получают с ним правильные результаты.
Два потока, обработанные двумя двумя разными потоками, вероятно, являются причиной того, что мы иногда видим сообщение ERROR
, напечатанное некоторыми библиотеки, которые мы используем, печатаем перед некоторыми утверждениями печати, которые мы должны были видеть в соответствии с порядком исполнения.
Вы можете сделать это, не прибегая к sed с помощью переменной переменной Bash , хотя, как указывает @ruah, это не будет работать в однострочной версии (без точки с запятой, разделяющей команды) , Я оставляю этот первый подход, потому что я думаю, что интересно, что он не работает в одной строке:
TTY=$(tty); who | grep "${TTY#/dev/}"
Это сначала помещает вывод tty
в переменную, а затем стирает /dev/
при использовании grep. Но без точки с запятой TTY
это не в среде к моменту bash делает переменное расширение / mangling для grep.
Вот версия, которая работает, потому что она порождает подоболочку с уже измененной средой (с TTY
):
TTY=$(tty) WHOLINE=$(who | grep "${TTY#/dev/}")
Результат оставлен в $WHOLINE
.
Вы можете сделать это следующим образом:
tid=$(tty | sed 's#/dev/##') && who | grep "$tid"
Обычно используется xargs , чтобы сделать вывод одной команды опцией другой команды. Например:
$ cat command1
#!/bin/sh
echo "one"
echo "two"
echo "three"
$ cat command2
#!/bin/sh
printf '1 = %s\n' "$1"
$ ./command1 | xargs -n 1 ./command2
1 = one
1 = two
1 = three
$
Но ... пока это был ваш вопрос, это не то, что вы действительно хотите знать.
Если вы не возражаете хранить свой tty в переменную, вы можете использовать переменную bash для замены:
$ tty=`tty`; who | grep -w "${tty#/dev/}"
ghoti pts/198 Mar 8 17:01 (:0.0)
(вы хотите использовать -w, потому что если вы находитесь на pts / 6, вы не должны видеть лоты pts / 60.)
Вы ограничены этим в переменной, потому что если вы попытаетесь поместить команду tty
в канал, она думает, что она больше не работает с терминалом.
$ true | echo `tty | sed 's:/dev/::'`
not a tty
$
Обратите внимание, что ничто в этом ответе пока не относится к bash. Поскольку вы используете bash, другим способом решения этой проблемы является замена процесса. Например, пока это не работает:
$ who | grep "$(tty | sed 's:/dev/::')"
Это делает:
$ grep $(tty | sed 's:/dev/::') < <(who)
Ответ Эдуардо правильный (и, как я писал это, появилось еще несколько хороших ответов), но я хотел бы объяснить, почему исходная команда терпит неудачу. Как обычно, set -x
очень полезно видеть, что на самом деле происходит:
$ set -x
$ who | grep $(echo $(tty) | sed 's/\/dev\///')
+ who
++ sed 's/\/dev\///'
+++ tty
++ echo not a tty
+ grep not a tty
grep: a: No such file or directory
grep: tty: No such file or directory
Это не полностью явное из вышеизложенного, но то, что происходит, заключается в том, что tty
выводит «не tty». Это связано с тем, что часть конвейера подается на выход who
, поэтому его stdin действительно не является tty. Это настоящая причина, по которой все остальные ответы работают: они выходят из tty
из-за конвейера, поэтому он может видеть ваш фактический терминал.
BTW, ваша предлагаемая команда в основном правильна (за исключением проблемы с конвейером) , но излишне сложный. Не используйте echo $(tty)
, это по сути то же самое, что только tty
.
"${TTY#/dev/}"
получает слишком рано. Вы должны сделать назначение переменной как отдельную команду (используя разрыв строки или;
или&&
или еще что-то). – ruakh 9 March 2012 в 16:42TTY
раньше. Благодарю. – Eduardo Ivanec 9 March 2012 в 16:45