Передать вывод предыдущей команды next в качестве аргумента

119

У меня есть команда, которая выводит данные в stdout ( command1 -p=aaa -v=bbb -i=4). Выходная строка может иметь следующее значение:

rate (10%) - name: value - 10Kbps

Я хочу получить этот вывод, чтобы сохранить этот показатель (я думаю, что труба будет полезна здесь). И, наконец, я хотел бы, чтобы эта скорость была значением параметра для второй команды (скажем command2 -t=${rate})

Это выглядит сложно на моей стороне; Я хотел бы лучше узнать, как использовать трубы, grep, sed и так далее.

Я пробовал много комбинаций, подобных этой, но я запутался в этих:

$ command1 -p=aaa -v=bbb -i=4 | grep "rate" 2>&1 command2 -t="rate was "${rate}
Павел
источник

Ответы:

144

Вы путаете два очень разных типа входов.

  1. Стандартный ввод ( stdin)
  2. Аргументы командной строки

Они разные и полезны для разных целей. Некоторые команды могут вводить данные обоими способами, но они обычно используют их по-разному. Возьмем для примера wcкоманду:

  1. Передача ввода по stdin:

    ls | wc -l
    

    Это будет считать строки в выводе ls

  2. Передача ввода аргументами командной строки:

    wc -l $(ls)
    

    Это будет считать строки в списке файлов, напечатанныхls

Совершенно разные вещи.

Чтобы ответить на ваш вопрос, звучит так, будто вы хотите зафиксировать скорость из выходных данных первой команды, а затем использовать скорость в качестве аргумента командной строки для второй команды. Вот один из способов сделать это:

rate=$(command1 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p')
command2 -t "rate was $rate"

Объяснение sed:

  • Команда s/pattern/replacement/должна заменить какой-то шаблон
  • Шаблон означает: строка должна начинаться с «rate» ( ^rate), за которым следуют любые два символа ( ..), за которыми следуют 0 или более цифр, после которых следует «a» %, а затем остальная часть текста ( .*).
  • \1под заменой подразумевается содержимое первого выражения, захваченного внутри \(...\), поэтому в этом случае цифры перед %знаком
  • -nФлаг sedкоманды означает не печатать строки по умолчанию. Символ « pв конце s///команды» означает печать строки, если произошла замена. Короче говоря, команда будет печатать что-то, только если было совпадение.
Янош
источник
13

Я склонен использовать это:

command1 | xargs -I{} command2 {}

Передайте вывод command1через xargs с помощью подстановки (фигурные скобки) в command2. Если command1 это findобязательно использовать -print0и добавить -0в xargsтечение нуля строки и xargsбудет вызывать command2для каждой вещи найдено.

В вашем случае (и взяв строку sed из @Janos):

command1 -p=aaa -v=bbb -i=4 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p' | xargs -I{} command2 -t="rate was {}"
Майкл Андерсон
источник
Это делает вещи красивыми и pipe'd, поэтому мне это нравится.
Матин Улхак
4

Чтобы смоделировать вывод command1я использую это выражение эха:

$ echo -e "Foo\nrate (10%) - name: value - 10Kbps\nBar"
$ alias command1='echo -e "Blah\nrate (10%) - name: value - 10Kbps\nBlag"'

Быстрый тест:

$ command1
Blah
rate (10%) - name: value - 10Kbps
Blag

Это все хорошо, так что давайте разберемся:

$ command1 | grep 'rate'
rate (10%) - name: value - 10Kbps

Таким образом, мы получаем нужную строку command1, давайте передадим ее в command2:

$ alias command2='echo'
$ command2 -t="rate was "$(command1 | grep 'rate')
-t=rate was rate (10%) - name: value - 10Kbps

Я ожидаю "rate was "$(command1 | grep 'rate')объединения автоматически. Если это не сработает из-за пробелов, вы должны вместо этого передать ввод:

$ alias command2='echo'
$ command2 -t=$(echo '"rate was ' $(command1 | grep 'rate') '"')
-t="rate was rate (10%) - name: value - 10Kbps "
user56452
источник
3

Попробуйте это с помощью & :

command | grep -oP '\$>\s+rate\s+\(\K[^\)]+'
Жиль Квено
источник
2

Первая задача - извлечь ставку из этой строки. С GNU grep (не встроенный Linux или Cygwin) вы можете использовать эту -oопцию. Часть, которую вы хотите, это та, которая содержит только цифры и сопровождается %знаком. Если вы не хотите извлекать %саму себя, вам нужен дополнительный трюк: предпросмотр с нулевой шириной , который ничего не соответствует, но только если за этим ничего не следует %.

command1 -p=aaa -v=bbb -i=4 | grep -o -P '[0-9]+(?=%)'

Другая возможность - использовать sed. Чтобы извлечь часть строки в sed, используйте sкоманду с регулярным выражением, которое соответствует всей строке (начиная с ^и заканчивая $), с частью, которую нужно сохранить в группе ( \(…\)). Замените всю строку содержанием группы (ов), чтобы сохранить. В общем, передайте -nопцию, чтобы отключить печать по умолчанию и поместить pмодификатор для печати строк, где есть что извлечь (здесь есть одна строка, так что это не имеет значения). См. Возврат только части строки после соответствующего шаблона и Извлечение регулярного выражения, сопоставленного с «sed», без печати окружающих символов для получения дополнительных уловок sed.

command1 -p=aaa -v=bbb -i=4 | sed 's/^.*rate(\([0-9]*\)%).*$/\1/'

Опять более гибкий, чем sed, это awk. Awk выполняет инструкции для каждой строки на небольшом императивном языке. Есть много способов извлечь ставку здесь; Я выбираю вторые поля (по умолчанию поля разделяются пробелами) и удаляю все символы в нем, которые не являются цифрами.

command1 -p=aaa -v=bbb -i=4 | awk '{gsub(/[^0-9]+/, "", $2); print $2}'

Следующий шаг, теперь, когда вы извлекли ставку, это передать ее в качестве аргумента command2. Инструментом для этого является команда susbtitution . Если вы поместите команду внутри $(…)(круглая скобка), ее вывод подставляется в командную строку. Вывод команды разбивается на отдельные слова в каждом блоке пробелов, и каждое слово рассматривается как шаблон с подстановочными знаками; если вы не хотите , чтобы это произошло, поставить двойные кавычки вокруг подстановки команд: "$(…)". В двойных кавычках выходные данные команды используются непосредственно в качестве единственного параметра (единственное преобразование состоит в том, что новые строки в конце выходных данных удаляются).

command2 -t "$(command1 -p=aaa -v=bbb -i=4 |
               sed 's/^.*rate(\([0-9]*\)%).*$/\1/')"
жилль
источник
0

Вы можете использовать grepи это PCRE - Perl-совместимые регулярные выражения. Это позволяет вам использовать вид сзади, чтобы соответствовать значению нормы, без включения строки «ставка» в ваши результаты при поиске.

пример

$ echo "rate (10%) - name: value - 10Kbps" | grep -oP '(?<=^rate \()\d+'
10

подробности

Вышеуказанное grepработает следующим образом:

  • -oвернет только то, что мы ищем \d+, то есть цифры в скобках.
  • -P включает функцию PCRE от grep
  • (?<=^rate \() будет возвращать только те строки, которые начинаются с "rate (")

command2

Чтобы поймать значение «скорость» вы можете запустить command1так:

$ rate=$(command 1 | grep -oP '(?<=^rate \()\d+'

Тогда для вашей второй команды вы просто используете эту переменную.

$ command2 -t=${rate}

Вы можете получить фантазию и сделать все это одной строкой:

$ command2 -t=$(command1 | grep -oP '(?<=^rate \()\d+')

Это выполнит command1 внутри $(..)исполнительного блока, возьмет его результаты и включит их в -t=..переключатель command2 .

SLM
источник
0

Я обычно использую `command`, чтобы разместить вывод в качестве аргумента для другой команды. Например, чтобы найти ресурс, потребляемый процессом foo на freebsd, будет:

procstat -r `pgrep -x foo`

Здесь pgrep используется для извлечения PID процесса foo, который передается команде procstat, которая ожидает PID процесса в качестве аргумента.

Вишал Саху
источник