Параметризуйте ланцюгові дзвінки на корисну програму в Bash


12

У мене чорна скринька UNIX-програми, яка використовується в оболонці Bash, яка читає стовпці даних зі stdin, обробляє їх (застосовуючи ефект згладжування), а потім виводить у stdout. Я використовую його як труби UNIX, як

generate | smooth | plot  

Для більшого згладжування я можу повторити плавне, тому його буде викликано з командного рядка Bash як

generate | smooth | smooth | plot   

або навіть

generate | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | plot

Це стає неприємним. Я хотів би зробити обгортку Bash, щоб мати можливість smoothпередавати та виводити свій результат прямо в новий примірник smoothдовільної кількості разів, щось подібне

generate | newsmooth 5 | plot

замість

generate | smooth | smooth | smooth | smooth | smooth | plot

Моєю першою спробою був сценарій Bash, який генерував тимчасові файли в поточному каталозі та видаляв їх, але це виявилося некрасивим, коли я не був у каталозі з доступом до запису, а також залишав файли сміття, коли переривався.

Аргументів до smoothпрограми немає.

Чи є більш елегантний спосіб "обгортати" таку програму, щоб параметризувати кількість дзвінків?


1
Я сподіваюся, що ваш приклад є вимушеною справою заради питання, а не фактичної потреби
arielnmz

Відповіді:


18

Ви можете включити його в рекурсивну функцію:

smooth() {
  if [[ $1 -gt 1 ]]; then # add another call to function
    command smooth | smooth $(($1 - 1)) 
  else
    command smooth # no further 
  fi
}

Ви б використовували це як

generate | smooth 5 | plot

що було б рівнозначно

generate | smooth | smooth | smooth | smooth | smooth | plot

Це ідеально, поводиться точно так, як потрібно. А тепер я дізнався про ключове слово bash "command".
Діана Вілбор

2
До речі, це той самий підхід, який я використовую в Як я кодую довільно довгий ланцюг труб? - і, задовго до цього, в обробці довгих списків редагування в xmlstarlet .
Чарльз Даффі

5

Якщо ви можете дозволити ввести стільки коми, скільки потрібних smoothкоманд, ви можете скористатися розширенням Brace Excel, розділеним комами оболонки.

TL; ДОКТОР

Весь командний рядок для вашого зразка буде таким:

generate | eval 'smooth |'{,,,,} plot

Примітка:

  • додайте або видаліть коми, якщо ви хочете більше чи менше повторень smooth |
  • Там немає |до того, plotбо включено в останній smooth |рядку створюваного Brace розширення
  • ви також можете навести аргументи до smoothтих пір, поки ви зможете їх правильно включити в цитовану нерухому частину, яка передує відкритій дужці; у будь-якому випадку пам’ятайте, що ви надавали б їм усі повторення команди

Як це працює

Розділене комою розділене комами дозволяє динамічно створювати рядки, кожна з яких визначена фіксованою частиною плюс зазначені змінні частини. Вона виробляє стільки ж рядків , як існують різні деталі , зазначені, як a{b,c,d}виробляє ab ac ad.

Маленька хитрість тут полягає в тому, що якщо ви скоріше складете список порожніх змінних частин, тобто з комами всередині дужок, то Brace Expansion буде створювати лише копії фіксованої частини. Наприклад:

smooth{,,,,}

буде виробляти:

smooth smooth smooth smooth smooth

Зауважте, що 4 коми утворюють 5 smoothрядків. Ось так працює це розширення Brace: воно створює стільки коми, скільки один.

Звичайно, у вашому випадку вам також потрібно |розділити кожну smooth, тому просто додайте її у фіксовану частину, але подбайте про те, щоб правильно її цитувати, щоб оболонка не інтерпретувала її одразу. Це:

'smooth|'{,,,,}

буде виробляти:

'smooth|' 'smooth|' 'smooth|' 'smooth|' 'smooth|'

Слідкуйте за тим, щоб нерухому частину завжди розміщували безпосередньо поруч із відкритою підвіскою, тобто немає проміжків між ' та {.

(Зауважте також, що для формування фіксованої частини ви також можете використовувати подвійні лапки замість одинарних лапок, якщо вам потрібно розширити змінні оболонки у фіксованій частині. Просто подбайте про додаткові епізоди, які потрібні, коли трапляються спеціальні символи деяких оболонок всередині дворядкового рядка).

У цей момент вам потрібно eval застосувати до цього рядка, щоб оболонка остаточно інтерпретувала його як конвеєрну команду.

Таким чином, підсумовуючи це, весь командний рядок для вашого зразка буде таким:

generate | eval 'smooth |'{,,,,} plot

1
Існують значні занепокоєння щодо безпеки, якщо це застосовується в місцях параметризованого виклику. Дивіться мою відповідь на функцію рекурсивної башти та ітераційну побудову рядків "eval": що краще? на стеку Overflow.
Чарльз Даффі

1
@CharlesDuffy Я повністю погоджуюся з вашими занепокоєннями щодо маються на увазі ризиків щодо використання, evalколи ви надаєте ненадійні, не санізовані, рядки для його оцінки, тобто коли використовуєте змінні, які можуть містити "невідомий" вміст, як у випадку, з яким ви пов’язані. З іншого боку, evalце також може бути дуже зручним для швидкого «сантехнічного» виконання команд, особливо при використанні підказки, як здається у випадку, коли evalвведенням буде лише буквальна рядок, введена користувачем вручну особа
LL3

Як уже було помічено в інших місцях, ви завжди можете замінити eval strщось вибагливе і дурне, як . /dev/stdin <<<str. Це не тільки справить враження на дурнів, але й убереже @CharlesDuffy з вашої спини ;-)
pizdelect

1
@pizdelect, ви можете уважно прочитати попередній коментар LL3 - він збалансований, нюансований та розумний. (Дійсно, мій власний початковий коментар мав нюанси, які ви, мабуть, нехтуєте; "якщо він використовується у випадках, коли виклик параметризований", це вирішальне розрізнення: екземпляр LL3 не параметризований, що робить його безпечним).
Чарльз Даффі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.