Передайте висновок попередньої команди наступному як аргумент


118

У мене є команда, яка виводить дані в stdout ( command1 -p=aaa -v=bbb -i=4). Рядок виводу може мати таке значення:

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

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

На моєму боці це виглядає хитро; Мені хотілося б краще знати, як користуватися трубами, грейпом, sed і так далі.

Я спробував багато таких комбінацій, але я їх плутаю:

$ command1 -p=aaa -v=bbb -i=4 | grep "rate" 2>&1 command2 -t="rate was "${rate}

Відповіді:


143

Ви плутаєте два дуже різні типи входів.

  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 {}"

Це добре тримає речі, і саме тому мені це подобається.
Mateen Ulhaq

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 "


2

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

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

Інша можливість - використовувати sed. Щоб витягти частину рядка в sed, використовуйте sкоманду з регулярним виразом, який відповідає цілому рядку (починаючи з ^і закінчуючи $), а частину зберегти в групі ( \(…\)). Замініть весь рядок на вміст групи (груп), який потрібно зберегти. Загалом, пропустіть -nопцію вимкнення друку за замовчуванням і покладіть pмодифікатор на друк рядків, де є що витягнути (тут є один рядок, щоб це не мало значення). Див. Розділ Повернення лише частини рядка після узгодженого шаблону та Вилучення регулярного вираження, збіганого з '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. Інструментом для цього є командна субситуація . Якщо ви помістите команду всередину $(…)(долар-кругла дужка), її вихід замінюється в командний рядок. Вихід команди розбивається на окремі слова в кожному блоці пробілів, і кожне слово трактується як шаблон підстановки; якщо ви не хочете , щоб це відбулося, поставити подвійні лапки навколо підстановки команд: "$(…)". За допомогою подвійних лапок вихідна команда використовується безпосередньо як єдиний параметр (єдине перетворення полягає в тому, що нові рядки в кінці виводу видаляються).

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

0

Ви можете використовувати grepі це PCRE - регулярні вирази, сумісні з Perl. Це дозволяє використовувати погляд, який відповідає, щоб відповідати значенню ставки, без включення рядка "rate" у ваші результати під час прив'язки до нього.

Приклад

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

Деталі

Вищезазначене grepпрацює наступним чином:

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

команда2

Щоб зловити значення "rate", ви можете запустити command1так:

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

Тоді для другої команди ви просто використовувати цю змінну.

$ command2 -t=${rate}

Ви можете пофантазувати і зробити все це одним рядком:

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

Це виконає command1 всередині $(..)блоку виконання, візьме його результати та включить їх у -t=..перемикач command2 .


0

Я, як правило, використовую `команду`, щоб розмістити його як аргумент для іншої команди. Наприклад, знайти ресурс, споживаний процесом foo на freebsd, буде:

procstat -r `pgrep -x foo`

Тут pgrep використовується для отримання PID процесу foo, який передається команді procstat, яка очікує PID процесу в якості аргументу.

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