Использовать вывод команды bash (с pipe) в качестве параметра для другой команды - PullRequest
11 голосов
/ 09 марта 2012

Я ищу способ использовать вывод команды (скажем, command1) в качестве аргумента для другой команды (скажем, command2).

Я столкнулся с этой проблемой при попытке grep выводакоманды who, но с использованием шаблона, заданного другим набором команд (на самом деле tty передано по sed).

Контекст:

Если tty отображает:

/dev/pts/5

И who отображает:

root     pts/4        2012-01-15 16:01 (xxxx)
root     pts/5        2012-02-25 10:02 (yyyy)
root     pts/2        2012-03-09 12:03 (zzzz)

Цель:

Мне нужны только строки, относящиеся к "pts / 5", поэтому я отправил tty вsed следующим образом:

$ tty | sed 's/\/dev\///'
pts/5

Тест:

Попытка выполнить следующую команду не работает:

$ who | grep $(echo $(tty) | sed 's/\/dev\///')"

Возможное решение:

Я обнаружил, что следующее прекрасно работает:

$ eval "who | grep $(echo $(tty) | sed 's/\/dev\///')"

Но я уверен, что использования eval можно избежать.

В качестве последнего побочного узла: я заметил, что аргумент "-m" для who дает мне именно то, что я хочу (получить только строку who, которая связана с текущим пользователем).Но мне все еще любопытно, как я могу заставить эту комбинацию каналов и командное вложение работать ...

Ответы [ 4 ]

10 голосов
/ 09 марта 2012

Обычно используется 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)
6 голосов
/ 09 марта 2012

@ Ответ Эдуардо верный (и когда я писал это, появилась пара других хороших ответов), но я хотел бы объяснить, почему исходная команда не выполняется.Как обычно, 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, поэтому его стандартный ввод не является tty.Это реальная причина, по которой все остальные работают: они выводят tty из конвейера, поэтому он может видеть ваш фактический терминал.

Кстати, ваша предложенная команда в основном верна (за исключением проблемы с конвейером),но излишне сложный.Не используйте echo $(tty), это по сути то же самое, что и tty.

5 голосов
/ 09 марта 2012

Вы можете сделать это, не прибегая к sed, с помощью Переменные Bash , хотя, как указывает @ruakh, это не сработает в однострочной версии (без точки с запятой, разделяющей команды).Я оставляю этот первый подход, потому что я думаю, что интересно, что он не работает в одной строке:

TTY=$(tty); who | grep "${TTY#/dev/}"

Это сначала помещает вывод tty в переменную, а затем стирает ведущие/dev/ о том, как это использует grep.Но без точки с запятой TTY это не в среде к моменту, когда bash выполняет расширение / искажение переменной для grep.

Вот версия, которая работает, потому что она порождает подоболочку суже измененная среда (которая имеет TTY):

TTY=$(tty) WHOLINE=$(who | grep "${TTY#/dev/}")

Результат остается в $WHOLINE.

2 голосов
/ 09 марта 2012

Вы можете сделать это так:

tid=$(tty | sed 's#/dev/##') && who | grep "$tid"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...