Комментарии 30
одни люди борются с башизмами, другие пишут о них статьи
мифическую совместимость непонятно с чем
из 6 систем с linux у меня на столе bash есть на 2 (на 3 из 7, если считать android за linux-систему).
за freebsd не слежу, там уже появился bash в дефолтной установке?
с кучей лишних действий и абсолютно нечитаемыми конструкциями
можно подумать, что массивы bash — верх читаемости.
и что, кроме классического bourne shell и bash больше скриптовых языков нет?
ИМХО если потребовались массивы, то это уже повод задуматься о другом языке программирования.
P. S. я не говорю, что башизмы — вселенское зло и их никогда нельзя использовать; это как goto и глобальные переменные — иногда делают жизнь лучше, но в целом нужно стремиться избегать.
из 6 систем с linux у меня на столе bash есть на 2Расскажите, пожалуйста, что за дистрибутивы такие, в которых нет bash. Только не надо про всякое embedded с busybox.
и что, кроме классического bourne shell и bash больше скриптовых языков нет?Замените башизмы на zsh-измы, fish-измы или что вам больше нравится.
если потребовались массивы, то это уже повод задуматься о другом языкеАргументируйте.
это как goto и глобальные переменныеСравнивать массивы с goto это, конечно, мощно. Ну, можете избегать массивов и дальше, удачи вам с обработкой сотни тысяч строк в каком-нибудь однострочнике, который надо написать за пару минут.
удачи вам с обработкой сотни тысяч строк в каком-нибудь однострочнике, который надо написать за пару минут.
Например? Где необходим массив, там будет его заполнение и какая-то обработка (как минимум 2 конструкции, похожие на цикл). Однострочник такого размера выглядит достаточно неприятно (для меня), чтобы решать эту задачу другим способом.
Пример, возьмем стандартную итерацию по куче строк (тут не особо важно из файла или stdin, но я для простоты беру миллион строк из файла):
while read -r line; do
echo "$line changed" >> output.txt
done < 1m_lines.txt
Это на моей машине выполняется за 44 секунды.
Теперь используем массивы из баша:
readarray -t lines < 1m_lines.txt
for i in "${!lines[@]}"; do
lines[$i]="${lines[$i]} changed"
done
printf "%s\n" "${lines[@]}" > output.txt
Больше писать, но выполнение за 10 сек, выигрыш в 4 раза.
Понятно, что такой пример это сферический конь в вакууме, который меняется на банальный sed, но в реальных задачах логика бывает куда сложнее и этим уже не обойтись, массивы сильно улучшают как удобство работы с кучей данных, так и скорость. То же самое справедливо и для других башизмов.
Больше писать, но выполнение за 10 сек, выигрыш в 4 раза.Хм, есть же вариант, когда и меньше писать, на один символ, и без всяких этих ваших «башизмов», чистый POSIX.
while read -r line; do
echo "$line changed"
done < /tmp/1m_lines.txt > /tmp/output-out.txt
Общее время: 0m17.949s против 1m46.314s, 6 раз. Кстати, хотя общее время этого варианта такое же, как у башизнутого варианта, но по процессорному времени, POSIX вариант в 1,24 раза быстрее башизнутого.
Во-вторых, массивы это не просто красивая обертка для чтения кучи строк, они также позволяют достаточно гибко с ними работать — ссылаться на конкретный элемент по индексу или ключу, добавлять или удалять элементы в любых местах, мгновенно узнавать их количество.
P.S. Не смог повторить ситуацию, когда баш вариант сожрал больше процессора, в обоих случаях плюс-минус одно и то же, POSIX вариант незначительно медленнее.
Во-первых, эти варианты при практическом использовании не равнозначны
Равнозначны. Медленный вариант 1 000 000 раз открывает/закрывает файловый дескриптор — вот и весь секрет медленности.
Во-вторых, массивы это не просто красивая обертка для чтения кучи строк
Не возражаю. Я и раньше знал, что массивы в bash есть, но зачем они там нужны — неизвестно. Просто как только у меня возникает задача, в которой нужно что-то делать с массивами — желание сделать это в bash сразу пропадает;) На десктопе — есть oocalc и python, там всё это значительно легче.
Не смог повторить ситуацию, когда баш вариант сожрал больше процессора, в обоих случаях плюс-минус одно и то же, POSIX вариант незначительно медленнее.Я Вас умоляю! Очевидно ж, это ж зависит от длины строк. Для понимания, что массивы bash это только синтаксический сахар и ничего больше, в деле «башизмов» можете опробовать следующий код:
readarray -t lines < /tmp/1m_lines.txt
printf "%s changed\n" "${lines[@]}" > /tmp/output-bash1.txt
Который в 2...3 раза короче и шустрее вашего, поскольку не имеет хотя бы цикла.А заодно, и подумать над вопросом: «Почему нормальные реализации массивов в POSIX awk, а так же в perl или python, входящие в стандарт Linux, выполняют эту же задачу на два порядка быстрее?»
Да, забытый POSIX вариант, вероятной самый шустрый из всех чисто shell/bash вариантов:
IFS='
'
printf "%s changed\n" $(cat /tmp/1m_lines.txt) > /tmp/output-pos.txt
Да хотя бы джавистам, которые до сих пор свои JAVA_OPTS собирают конкатенацией строк, вместо того, чтобы пользоваться массивом.
$ man sh
...
If bash is invoked with the name sh, it tries to mimic the startup
behavior of historical versions of sh as closely as possible, while
conforming to the POSIX standard as well...
... posix mode...
И не говоря уж за Solaris/AIX/FreeBSD/… Говорят, Java многоплатформенная ж…
В статье Вы не упомянули о различии в обработке
Упомянули, но одним коротким абзацем без примеров.
${arr[*]}
${arr[@]}
"${arr[*]}"
"${arr[@]}"
Например:
x=( "hello world" "I am" bash )
# каждое слово в отдельной строке
printf "%s\n" ${x[*]}
printf "%s\n" ${x[@]}
# все слова в одной строке
printf "%s\n" "${x[*]}"
# каждый элемент массива в отдельной строке
printf "%s\n" "${x[@]}"
Дополнение. На самом деле автор упомянул об этом — я не заметил этот абзац в тексте:
Обратите внимание, что символ "@" может быть использован вместо "" в конструкциях типа {arr[]}, результат будет одинаковым за исключением разворачивания записи в кавычках. "$" и "$@" выведут записи в кавычках, "${arr[]}" вернет каждую запись как одно слово, "${arr[@]}" вернет каждую запись в виде отдельных слов.
-нет
-пьете?
-нет
-на bash пишиете?
-нет
— ну тогда это очень усложняет диагностику заболевания )))))
#initialising
declare -A arr
arr[some_string]=test1
arr[some_string2]=test2
arr[1234]=test3
#values out
$ echo ${arr[@]}
test2 test3 test1
#keys out
$ echo ${!arr[@]}
some_string2 1234 some_string
возможно, вы не знакомы с такой полезной особенностью bash как массивыИзвините, но что у Вас с русским языком? Вот не удержался, глаза режет.
Особенность — характерное, отличительное свойство кого-/чего-нибудь.С каких пор массивы — это «отличительная» черта Bash? Массивы есть во многих языках, и Bash тут совсем не исключение. Их наличие нисколько не делает Bash особенным.
… you may not be familiar with bash's array feature.В данном контексте «bash's feature» — это, скорее, «часть языка Bash» [1].
[1] dictionary.cambridge.org/ru/словарь/английский/feature
С каких пор массивы — это «отличительная» черта Bash?
По сравнению с sh. Сравнивать bash с любым другим языком вряд ли имеет смысл.
В bash ассоциативные массивы появились недавно (по меркам линукса). Но гораздо гораздо раньше они уже активно и удобно использовались в перл, а потом в питон.
Поэтому ладно еще обычные массивы, бывает полезно. Но ассоциативные завезли и хорошо. Нет смысла это особо хайлайтить, потому что любые более-менее сложные задачки лучше писать на других языках.
А баш оставить для стандартной штуки, а именно — удобство и автоматизация работы в CLI, плюс административные штуки и инсталляционные скрипты.
Круто! Не знал что так можно.
Массивы bash