Маніпулювання струнними баш-ланцюгами


9

Я читав деякі інші питання з маніпулювання стрункою bash string, але вони здаються спеціалізованими програмами.

По суті, чи є спосіб зробити наступне простішим?

замість

$ string='hello world'; string2="${string// /_}"; echo "${string2^^}"
HELLO_WORLD

щось на зразок

$ echo 'hello world' | $"{-// /_}" | "${ -^^}"
HELLO_WORLD

Редагувати Мені цікаво залишатися в баш-маніпуляціях, якщо можливо, для підтримки швидкості (на відміну від sed / awk, які мають тенденцію сильно уповільнювати мої сценарії)

Edit2: @jimmij

Мені подобається другий приклад і привів мене до створення функції.

bash_m() { { read x; echo "${x// /_}"; } | { read x; echo "${x^^}"; }; }
echo hello world | bash_m
HELLO_WORLD

1
чому ви думаєте, чому sed / awk для цієї мети буде повільним? Вони так само швидко приходять.
mkc

1
@Ketan Sed і awk - це окремі процеси, тому вони ніколи не можуть бути швидкими, як щось, що баш може зробити споконвічно, не запускаючи окремий процес. Зазвичай ця різниця навряд чи помітна, але там, де важливість роботи в скриптах оболонки зазвичай є певним циклом, або обчислення повторюються дуже велика кількість разів, і нерестування тисяч процесів будуть помітно повільнішими, ніж робити просту маніпуляцію з рядком в основному.
jw013

2
@ jw013 Це справедливо для коротких рядків як "привіт світ" від питання, але якщо рядок дуже довгий, скажімо в trпосібнику, то навпаки, тому що час нерестування процесів незначний порівняно з часом маніпуляції рядками, для якого sedі awkприсвячені. Якщо рядок надзвичайно довгий, скажімо, весь посібник з bash, тоді bash може просто відмовитись від продовження дії через деякі внутрішні обмеження.
jimmij

2
@ Jw013 Я стверджуючи код маніпуляції рядки , яка Баша є менш ефективними , то виділеними коштами , як sed, awk, trабо аналогічними. Подивіться на відповідь gena2x, яку я відредагував певний час тому, додавши саме цю інформацію: unix.stackexchange.com/questions/162221/… ви можете порівняти її з відповіддю тердона на те саме запитання, де він дає час на короткі рядки, в яких нерестовий процес не потребує більшої кількості часу. Ви можете перевірити його самостійно та опублікувати результат.
jimmij

1
@Miati Чому ти вважаєш, що ця додаткова корисна read x; echo $xефективність? Синтаксис не виглядає коротшим і чистішим. x=${x// /_}; x=${x^^}набагато більш стислий спосіб зробити те саме, що і {read x; echo ${x.... Що стосується продуктивності, @jimmij вказував, що tr/ sedбуло б швидше, ніж bashкількість вилок рівна. Використання труби завжди призводить до додаткового процесу, тому аргумент збереження виделки більше не застосовується. Таким чином, якщо ви використовуєте труби, просто використовуйте sed/ trі т. Д. Якщо ви можете це зробити в башті, зробіть це і пропустіть цю read x; echo $xдурницю.
jw013

Відповіді:


9

Що сказав Джиммідж. Його останній приклад - найближчий ви можете дістатись до того, що ви намагаєтеся в своєму трубному виразі.

Ось варіант на цю тему:

echo 'hello world'|echo $(read s;s=${s^^};echo ${s// /_})

Я був би схильний до використання tr, оскільки це досить швидко.

echo 'hello world'|tr ' [:lower:]' '_[:upper:]'

Я припускаю, що шкода, що bash не дозволяє розширити вкладені параметри; OTOH, використання таких вкладених виразів може легко призвести до коду, який боляче читати. Якщо вам справді не потрібні речі, щоб вони пройшли якомога швидше, краще написати код, який легко читати, розуміти та підтримувати, а не розумний вигляд коду, який є PITA для налагодження. І якщо ви дійсно робите потрібні речі , щоб зробити на максимальній швидкості ви повинні використовувати скомпільований код, а НЕ скрипт.


7

Ви не можете передавати розширення параметрів таким чином. Якщо ви посилаєтесь на xвикористання $символу як у "${x}"формі, то це має бути справжнє ім'я змінної, а не стандартне введення, принаймні, не в bash. У zshви можете виконувати вкладені підстановки параметрів наступним чином:

$ x=''hello world'
$ echo ${${x// /_}:u}
HELLO_WORLD

(Примітка: :uдля zshтого ж, що і ^^для bash)

Вкладати в bash неможливо, і я думаю, що те, про що ви писали, є найкращим, що можна отримати, але якщо з будь-якої дивної причини вам потрібно залучати труби до рівняння, тоді ви можете спробувати це:

$ echo 'hello world' | { read x; echo "${x// /_}"; } | { read y; echo "${y^^}"; }
HELLO_WORLD

1
Враховуючи нашу нещодавню розмову про те, як tr/ sedшвидше, ніж bashпри обробці рядків, і враховуючи, як ви використовуєте труби для передачі рядків за допомогою стандартного вводу-виводу, я бачу буквально нульовий сенс робити ці операції в bash на відміну від tr/ sed. Чому б хтось колись | { read x; echo $x... }на противагу тому, | sedщо робить те саме?
jw013

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