Почему этот `grep -v` не работает должным образом?


12

У меня странная проблема, связанная с grep -vзапросами. Позвольте мне объяснить:

Для отображения подключений я использую who:

$ who
harry    pts/0        2016-12-08 20:41 (192.168.0.1)
james    pts/1        2016-12-08 19:28 (192.168.0.1)
timothy  pts/2        2016-12-08 02:44 (192.168.0.1)

Ток ttyмоего терминалаpts/0

$ tty
/dev/pts/0
$ tty | cut -f3-4 -d'/'
pts/0

Я пытаюсь исключить мою собственную связь, используя grep -v $(tty | cut -f3-4 -d'/'). Ожидаемый вывод этой команды должен быть whoбез моего подключения. Однако вывод наиболее неожиданный:

$ who | grep -v $(tty | cut -f3-4 -d'/')
grep: a: No such file or directory
grep: tty: No such file or directory

Я заключил $(...)в кавычки, и это, кажется, решить проблему "Нет такого файла или каталога". Тем не менее, мое соединение все еще печатается, хотя мой tty ( pts/0) должен был быть исключен:

$ who | grep -v "$(tty | cut -f3-4 -d'/')"
harry    pts/0        2016-12-08 20:41 (192.168.0.1)
james    pts/1        2016-12-08 19:28 (192.168.0.1)
timothy  pts/2        2016-12-08 02:44 (192.168.0.1)

На данный момент я абсолютно не знаю, почему grepзапрос работает неправильно.


4
Как насчет использования set -xсначала ... Затем запустите свою команду и посмотрите, что вы на самом деле пытаетесь grep...
don_crissti

@don_crissti ах, понятно; это говорит мне, что я на самом деле grep"не TTY". Как бы вы посоветовали мне обойти это?
perhapsmaybeharry

используйте переменную: tldp.org/HOWTO/Bash-Prompt-HOWTO/x721.html
don_crissti

Ответы:


18

Захари объяснил источник проблемы.

Хотя вы можете обойти это с

tty=$(tty)
tty_without_dev=${tty#/dev/}
who | grep -v "$tty_without_dev"

Это было бы неправильно, как, например, если это tty pts/1, вы бы в конечном итоге исключили все строки, содержащие pts/10. В некоторых grepреализациях есть -wвозможность поиска по слову

who | grep -vw pts/1

не будет соответствовать, pts/10потому что за pts/1ним не следует символ, не состоящий из слов.

Или вы можете использовать awkдля фильтрации на точное значение второго поля, как:

who | awk -v "tty=$tty_without_dev" '$2 != tty'

Если вы хотите сделать это одной командой:

{ who | awk -v "tty=$(tty<&3)" '$2 != substr(tty,6)'; } 3<&0

Исходный stdin дублируется на файловый дескриптор 3 и восстанавливается для ttyкоманды.


3
+1 за выяснение того, как сделать это в одной команде и указание на эту ошибку.
Захари Брейди

Еще один лайнер:tty | cut -f3-4 -d'/' | xargs -I % sh -c "who | grep -v %"
Axxis

20

Со страницы tty info.

'tty' печатает имя файла терминала, подключенного к его стандартному входу. Он печатает `не tty ', если стандартный ввод не является терминалом.

Проблема в том, что в вашем примере tty's stdin - это канал, а не ваш терминал.

Вы можете видеть из этого примера.

$ tty
/dev/pts/29
$ echo | tty 
not a tty

Чтобы обойти это, вы можете сделать что-то вроде этого.

who | grep -wv "$(ps ax | awk "\$1 == $$ {print \$2}" )"

Существует более быстрый / более эффективный способ, однако он требует двух команд.

t=$(tty)
who|grep -wv "${t:5}"

@ Кристофер, ты единственный, кто зашел на свой компьютер?
Захари Брэйди

@ Кристофер, странный. Таким образом, who | grep -v "$(ps ax | grep "^$$" | awk '{ print $2 }')"выдает ожидаемый результат на моей коробке и t=$(tty) who|grep -v "${t:5}"ничего не производит.
Захари Брейди

Какую оболочку / версию вы используете? GNU bash, version 4.1.2
Захари Брейди

2
ps ax | grep "^ *$$"может совпадать, например, ваша оболочка 123 и 1234 существует; ps ax -otty= $$является более надежным и только один процесс. Но я предпочитаю вашу ${t:5}или Стефана ${t#/dev/}(или substr(t,6))
dave_thompson_085

1
Пожалуйста, не добавляйте отказ от ответственности. Хотя намерения похвальны, они на самом деле не помогают ответ. Если кто-то указывает на ошибку в вашем ответе, просто отредактируйте свой ответ, чтобы включить исправление.
Terdon
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.