Манипулирование колонной

9

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

По сути, есть ли способ сделать ниже проще?

вместо

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

что-то вроде

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

Edit Я заинтересован в том, чтобы оставаться в рамках манипуляций с bash, если это возможно, чтобы поддерживать скорость (в отличие от sed / awk, которые имеют тенденцию значительно замедлять мои сценарии)

Edit2: @jimmij

Мне нравится второй пример, и он привел меня к созданию функции.

bash_m() { { read x; echo "${x// /_}"; } | { read x; echo "${x^^}"; }; }
echo hello world | bash_m
HELLO_WORLD
Miati
источник
1
почему вы думаете, что sed / awk будет медленным для этой цели? Они так быстро, как они приходят.
MKC
1
@Ketan Sed и awk - это отдельные процессы, поэтому они никогда не могут быть быстрыми, как то, что bash может сделать изначально без запуска отдельного процесса. Обычно эта разница едва заметна, но там, где производительность имеет значение в сценариях оболочки, как правило, это определенный цикл, или вычисления повторяются очень много раз, и порождение тысяч процессов будет заметно медленнее, чем простое манипулирование строками в bash.
jw013
2
@ jw013 Это верно для коротких строк как «привет мир» из вопроса, но если строка очень длинная, скажем, trруководство, то обратное верно, потому что время порождения процессов незначительно по сравнению со временем манипуляции строк, для которого sedи awkпосвящены. Если строка очень длинная, скажем, вся инструкция по bash, тогда bash может просто отказаться от продолжения, из-за некоторых внутренних ограничений.
Джимми
2
@ jw013 Я утверждая код манипуляции строки , которая Баша является менее эффективными , то выделенными средствами , как sed, awk, trили аналогичными. Посмотрите на ответ gena2x, который я редактировал некоторое время назад, добавив именно эту информацию: unix.stackexchange.com/questions/162221/… вы можете сравнить его с ответом terdon на тот же вопрос, где он дает время для коротких строк, в которых процесс нереста занимает больше всего времени. Вы можете проверить это самостоятельно и опубликовать результат.
Джимми
1
@Miati Почему вы думаете, что это дополнение read x; echo $xлучше для производительности? Синтаксис не выглядит короче или чище. x=${x// /_}; x=${x^^}это гораздо более краткий способ сделать то же самое, что и {read x; echo ${x.... Что касается производительности, то @jimmij указал, что tr/ sedбудет быстрее, чем число bashразветвлений, равное. Использование канала всегда приводит к дополнительному процессу, поэтому аргумент сохранения разветвления больше не применяется. Таким образом, если вы используете каналы, просто используйте sed/ trи т.д. Если вы можете сделать это в bash, сделайте это и пропустите эту 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. И если вы действительно делаете нужны вещи , чтобы сделать на максимальной скорости вы должны использовать скомпилированный код, а не скрипт.

PM 2Ring
источник
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
jimmij
источник
1
Учитывая наш недавний разговор о том, как tr/ sedбыстрее, чем bashпри обработке строк, и о том, как вы используете каналы для передачи строк через стандартный ввод / вывод, я вижу буквально нулевую точку для выполнения этих операций в bash, в отличие от tr/ sed. Почему человек | { read x; echo $x... }в отличие от | sedтого, кто делает то же самое?
jw013
1
@ jw013 честно говоря, я не вижу смысла. Это всего лишь пример принудительного вовлечения каналов в проблему, потому что OP явно просил их и не хотел использовать внешние программы (и то, echoи другое readвстроено в bash, поэтому в принципе немного быстрее). Как я уже писал в ответе, прогрессивные манипуляции с параметрами, которые имеет OP в этом вопросе, являются наилучшими, на мой взгляд, для этой задачи в bash. В любом случае проблема довольно академическая.
Джимми