Чому цей `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". Як ти запропонував би мені обійти це?
можливо, можебухарі

використовувати змінну: 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.

'tty' друкує ім'я файлу терміналу, підключеного до його стандартного входу. Він друкує `not tty ', якщо стандартний ввід не є терміналом.

Проблема полягає в тому, що у вашому прикладі stty 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}"

@Christopher Ви єдиний, хто ввійшов у свій комп’ютер?
Захарій Брейді

@Christopher, дивно. Тож 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)
Стефановим

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