Привет, Хабр! В мире автоматизации часто возникает вопрос: писать скрипт на Bash или на Python? Оба инструмента подходят отлично, но принципиально разные. Bash - больше про "скоропись", для системных задач, где важна скорость и краткость. Python же - универсальный язык, который намного лучше справляется со сложной логикой и структурами данных. Но когда лучше выбрать один, а когда - другой?
Некоторые задачи в Bash решаются одной строкой, когда же на Python потребуется десяток строк кода. При усложнении сценария - Bash превращается в головоломку из awk
, sed
и прочих, что значительно усложняет поддержку. В данной статье сравним подходы и определим, когда и какой язык лучше использовать.
Введение
Python - универсальный язык, но иногда Bash справится с задачей в разы быстрее и лаконичнее. Особенно в данных ситуациях:
Работа с файлами (поиск, замена, обработка)
Вызов системных утилит (
grep
,awk
,sed
,find
и тд.)Интеграция с системными утилитами (
systemctl
,top
и тд.)Конвейерная обработка данных (пайплайны, перенаправление вывода)
Но и у Bash есть слабые места: он не очень хорошо работает со сложными структурами данных (JSON, XML), сложно масштабируется, а код быстро становится нечитаемым.
Анализ: когда выигрывает Bash, а когда Python незаменим
1. Обработка логов: сравнение подходов
Bash:
grep ' 500 ' /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -5
Преимущества:
Быстрая скорость обработки (особенно ощутимо на больших файлах)
Минимальное потребление памяти (потоковая обработка)
Недостатки:
Хрупкость (зависимость от формата логов)
Сложность доработки (например, если нужно добавить фильтр по дате)
Плохая читаемость при усложнении логики
Python:
from collections import defaultdict
import re
log_file = "/var/log/nginx/access.log"
ip_counts = defaultdict(int)
log_pattern = re.compile(r'^(\S+) \S+ \S+ \[(.*?)\] "(.*?)" (\d+)')
with open(log_file) as f:
for line in f:
match = log_pattern.match(line)
if match and match.group(4) == "500":
ip = match.group(1)
ip_counts[ip] += 1
top_ips = sorted(ip_counts.items(), key=lambda x: x[1], reverse=True)[:5]
for ip, count in top_ips:
print(f"{count}\t{ip}")
Преимущества:
Четкая структура парсинга через регулярные выражения
Легкость добавления дополнительной логики (фильтрация по дате, URL и т.д.)
Возможность обработки некорректных строк
Лучшая читаемость кода
Недостатки:
Больший объем кода
Требуется больше памяти для обработки
Ощутимо медленнее на очень больших файлах
Вывод: для разовых задач на знакомых логах Bash явно предпочтительнее. Для сложного же анализа с большей гибкостью - Python.
2. Массовое переименование файлов
Bash:
# Безопасная версия с проверками
find . -maxdepth 1 -name "*.txt" -print0 | while IFS= read -r -d '' file; do
new_name="${file// /_}"
[ "$file" != "$new_name" ] && mv -- "$file" "$new_name"
done
Нюансы:
Обработка файлов с пробелами и спецсимволами через
-print0
Защита от переименования в то же имя
Поддержка рекурсивного поиска через
find
Python:
import os
from pathlib import Path
for item in Path('.').glob('*.txt'):
new_name = item.name.replace(' ', '_')
if new_name != item.name:
item.rename(item.with_name(new_name))
Нюансы:
Не переименовывает файлы без изменений
Использует современный pathlib вместо os
Кросс-платформенность
Производительность (возможно незначительное отклонение +-0,1с):
На 1000 файлах: Bash - 0,2с, Python - 0,5с
На 10000 файлах: Bash - 2,1с, Python - 4,8с
Вывод: для простых случаев Bash в разы быстрее, но Python предлагает более надежное решение для сложных сценариев.
3. Мониторинг диска
Bash:
#!/bin/bash
threshold=90
recipient="admin@example.com"
partition="/"
usage=$(df --output=pcent "$partition" | tail -1 | tr -d '% ')
message="Disk usage on $(hostname) for $partition: ${usage}%"
if [ "$usage" -ge "$threshold" ]; then
echo "$message" | mail -s "Disk Alert" "$recipient"
# Дополнительно: логирование и система повторов
logger -t disk_alert "$message"
fi
Python:
import smtplib
import socket
from email.mime.text import MIMEText
from shutil import disk_usage
def send_alert(usage):
host = socket.gethostname()
msg = MIMEText(f"Disk usage on {host}: {usage}%")
msg['Subject'] = 'Disk Alert'
msg['From'] = 'monitoring@example.com'
msg['To'] = 'admin@example.com'
with smtplib.SMTP('smtp.example.com') as server:
server.send_message(msg)
def main():
threshold = 90
partition = '/'
total, used, _ = disk_usage(partition)
usage_percent = (used / total) * 100
if usage_percent >= threshold:
send_alert(round(usage_percent, 1))
# Дополнительные функции:
# - Логирование
# - Очередь сообщений
# - Повторы при ошибках
if __name__ == '__main__':
main()
Критерии выбора:
Критерий |
Bash |
Python |
---|---|---|
Скорость разработки |
Быстрее для простых случаев |
Требует больше кода |
Поддержка |
Сложнее поддерживать |
Легче развивать |
Надежность |
Хрупкий |
Более устойчивый |
Возможности |
Ограниченные |
Полноценные приложения |
Портируемость |
Только Unix |
Кроссплатформенный |
4. Обработка CSV-файлов
Для полноты картины поставим задачу: посчитать среднее значение по второму столбцу CSV
Bash:
awk -F',' 'NR>1 {sum+=$2; count++} END {print sum/count}' data.csv
Python:
import pandas as pd
df = pd.read_csv('data.csv')
print(df.iloc[:, 1].mean())
Сравнение:
Bash: 0.8с при файле в 100МВ
-
Python: 1.2с, но с поддержкой:
Пропущенных значений
Разных форматов CSV
Дополнительной аналитики
5. Производительность: тесты на реальных данных
Домашний тестовый стенд:
Ubuntu 20.04
Intel Core i7-10750H
32GB RAM
SSD NVMe
Результаты:
Операция |
Bash |
Python |
Относительная разница |
---|---|---|---|
Поиск в логах (1GB) |
1.2с |
3.8с |
Python в 3.2 раза медленнее |
Обработка 10k файлов |
2.1с |
5.4с |
Python в 2.6 раза медленнее |
Анализ CSV (100MB) |
0.8с |
1.2с |
Python в 1.5 раза медленнее |
Сложная ETL-задача |
- |
4.2с |
Bash не справился |
Итоги
Использовать Bash в случаях, когда:
Требуется быстрое решение для одноразовой задачи
Работа с текстовыми потоками и системными утилитами
Необходима максимальная производительность на простых операциях
Скрипт будет выполняться только в Unix-окружении
Выбирать Python, когда:
Требуется сложная логика обработки данных
Важна читаемость кода
Необходима кроссплатформенная совместимость
Предполагается дальнейшее развитие скрипта
Планируется работа со структурированными данными (JSON, XML, CSV)
Со своей же стороны добавлю. Я часто использую "гибридный" подход. Комбинирование языков даёт максимальную эффективность: Bash - для быстрой предобработки данных, Python - для сложного анализа.
P.S. Я веду свою группу в Телеграмм, буду рад видеть всех, кому интересен процесс написания скриптов и автоматизация в мире IT.
Комментарии (29)
apevzner
18.07.2025 13:36Шелловские скрипты становятся очень хрупкими при работе с именами файлов, которые могут содержать пробелы...
skymal4ik
18.07.2025 13:36Избегаю скриптов на баше кроме разве что совсем простых на пару строк) из-за его, bash-a, синтаксиса. Простите за сквернословие, но назвать его могу только ублюдским.
Массивы, присваивание где нельзя ставить пробел между переменной и равно, все эти ne le ge , циклы - как будто против человечества всё это писалось. Понимаю, что наследие, традиции, ограничения, но прямо раздражает :)
vadimr
18.07.2025 13:36Не очень корректное сравнение. Python никак не мешает использовать сложные командные строки. Поэтому Python является скорее надстройкой над bash, чем альтернативой.
shoytov
18.07.2025 13:36У Python есть один явный минус в сравнении с bash - это виртуальное окружение. Далеко не все скрипты можно "вот так взять и просто написать" без использования сторонних библиотек, а для этого нужно создавать виртуальное окружение, прописывать полный путь к интерпретатору в этом окружении... То есть речи о переносимости "из коробки" тут быть не может.
skymal4ik
18.07.2025 13:36Часть библиотек есть в репозиториях ОС, иногда проще ставить их, чем возиться с виртуальными окружениями. Понятно, что не всё есть и версии старее, но иногда этого достаточно.
shoytov
18.07.2025 13:36нет, дорогой друг, ставить какой-то пакет питона в "стандартное" окружение ОС - это путь в никуда, если вы собираетесь прожить с этой системой хоть пару лет (со всеми обновлениями безопасности и т.д,) Никогда! Повторю, НИКОГДА, не нужно ставить какие-то пакеты в окружение python вашего дистрибутива. Нет, я не выпендриваюсь, честно, просто это - опыт.
P.S. python - мой рабочий инструмент более 10 лет, я его искренне люблю и лелею, но нет - для задач переносимой автоматизации он подходит едва ли...
Exinker
18.07.2025 13:36В чем проблема при установки утилиты создать окружение, указывать до него относительный путь, добавлять symlinks и прочее?
shoytov
18.07.2025 13:36ну тут go больше python уже подойдет, чтобы меньше телодвижений было. Дело, конечно, каждого, как извращаться. Как говорится "можно и зайца научить курить, но нафига?". Так и тут: bash - понятный POSIX инструмент, здесть P (Portable) является ключевым. Для каждой задачи должен подходить свой инструмент. Если задача требует программирования, то надо смотреть на накладные расходы. Никогда нет супер правильного решения - есть только компромиссы, с которыми мы готовы мириться
vadimr
18.07.2025 13:36Если задачу можно решить на голом баше, то на питоне без сторонних библиотек тем более можно.
shoytov
18.07.2025 13:36можно придумать такие кейсы. Например: считать информацию о загрузке процессора (CPU load) для каждого пользователя из
/proc/loadavg
и отсортировать их по убыванию средней нагрузки за последние 15 минут.
для меня в python видится использование библиотекиpsutil
(не входит в стандартную бибиотеку), а в bash это `awk '{for(i=1;i<=NF-2;i++) print $i}' /proc/loadavg | sort -nr`vadimr
18.07.2025 13:36Так вам и в питоне никто не мешает так же написать:
os.system("awk '{for(i=1;i<=NF-2;i++) print $i}' /proc/loadavg | sort -nr")
shoytov
18.07.2025 13:36да если делать вызов системных утилит - какой смысл использовать что-то другое) как я уже писал в другом комментарии выше - все можно сделать как угодно, все это будет компромисс, как хочется так и делай
vadimr
18.07.2025 13:36Смысл в том, что не всё можно сделать системными утилитами (или, по крайней мере, не всё легко сделать).
LexD1
18.07.2025 13:36Bash — командная оболочка (UNIX, GNU/Linux, MacOS).
Python — высокоуровневый язык программирования.
Сравнение кажется мне не особо корректным. Разным задачам — разные инструменты.
P.S. Но заголовки в стиле "versus" нравятся, хоть и маркетинг.
P.P.S. «Bash vs Golang» # ?
Darkholme
18.07.2025 13:36А если предположить, что вы работаете с автоматизацией в Linux, и у вас из инструментов как раз bash и python? И задачи как раз не сверхсложные, но далеко не всегда простые. Спасибо, на парсить YAML/JSON на bash я желанием не горю, да и в некоторых местах без Python никуда (например, модули к системам автоматизации)
eternaladm Автор
18.07.2025 13:36Спасибо за комментарий! Если рассматривать с подобной стороны - определенно факт. Я же хотел сравнить использование под те или иные задачи на Linux. Фактически, все задачи можно решить на одном bash, не городить окружения и тд, но ведь с точки зрения удобства подходы будут отличаться.
Ninil
18.07.2025 13:36Согласен с предыдущем коментарием.
ПыСыуже было на хабре
по всей видимости эффект от чатаЖПТ и иже с ними + "эффект ваАйТишников" уже провел к тому, что появилось много людей, не видящих абсурдности тем, подобных теме этой статьи.
eternaladm Автор
18.07.2025 13:36Спасибо за комментарий!
уже было на Хабр
Попробуйте найти через поисковик статьи, например, «о пользе высшего в IT». Вы будете крайне удивлены их количеству. Это касается в целом большинства тем.
по всей видимости эффект от чатаЖПТ и иже с ними + "эффект ваАйТишников"
Раскройте понятия, пожалуйста. Не понимаю, что за «эффекты».
andrey0700
18.07.2025 13:36К статье есть много замечаний.
Не нашёл описания методологии выполнения тестирования. Как замерялось время (timeit в Python, time в Bash?), сколько проходов каждого теста использовалось для усреднения результатов? Использовались ли одни и те же файлы, либо же каждый раз создавались новые?
Воспроизводимость. Куски кода, это хорошо, но желательно ещё добавить ссылку на репозиторий с проектом тестирования, чтобы любой желающий мог проверить результаты через автоматизированный скрипт работающий с создаваемой на лету tmpfs. Скажем так, те, кто ходил по врачам и знакомы с понятием доказательной медицины (включая такие понятия как предвзятость), скорее всего пройдут мимо этой статьи, пролистав её до конца.
Путаница в терминологии. Вы сравниваете не Bash и Python, а библиотеки Python и команды UNIX-подобных систем. Они никакого отношения непосредственно к языкам не имеют. Например, Awk — это вполне самостоятельный парсер, который ничего не мешает вызывать напрямую из Python минуя командный интерпретатор. А pandas в Python не входит, в Python входит модуль csv.
Неправильно подобранные решения/алгоритмы для сравнения. При анализе логов в Python используется медленная регулярка, а в Bash — нет. Самым примитивным решением в Python будет split() для разделения на колонки, а не регулярки. В случае сокетов и использования disk_usage из shlibs вообще не должно быть сильно большой разницы между языками, как мне кажется. Там всё будет зависеть больше от скорости работы системных вызовов и работы почтового сервера (в том числе всевозможных задержек). Поэтому сразу возникает вопрос, а что тут замерялось-то со стороны языков? А если скрипт многократно запускался, то у Python инициализация самого интерпретатора и модулей в разы медленнее, чем у Bash (см. ниже).
Собственно, инициализация интерпретатора в Bash намного быстрее, чем в Python. Но это касается лишь инициализации, а не длительной работы скрипта. То есть многократный запуск маленького быстрого скрипта на Python будет медленнее, чем на Bash. Это учитывалось? В статье эта информация должна быть отражена, поскольку может оказывать значительное влияние на само тестирование, искажая его результаты.
eternaladm Автор
18.07.2025 13:36Спасибо аз комментарий! Обратная связь очень помогает делать материалы более качественным.
Ваше замечание полностью справедливо, стоило внести эту информацию в статью. Для Python использоваться timet, для Bash - time. Проходов было 3, файлы же использовались одни и те же.
Момент с созданием репозитория рассмотрю в обязательном порядке, данный пункт действительно был упущен.
Что касательно путаницы в терминологии... Вы правы, фактически я противопоставлял 2 разных подхода. Методологическая ошибка, которая может ввести в заблуждение.
Да, мой пример с регулярками для разбора логов в Pythn - не самый лучший выбор для демонстрации производительности, были примеры более корректные. Но в этом аспекте я сознательно пошёл на компромисс в пользу "универсальности", тк регулярки лучше справятся с "грязными" данными. В статье данный момент действительно стоило оговорить, дабы не вводить в заблуждение.
И, про инициализацию интерпретатора - это наиболее важное замечание, которое мной было вообще упущено из виду. Разница в скорости запуска может быть критичной для каких-то сценариев.
Спасибо! Вы указали на все слабые места в статье, со всем согласен. Критика бесценна. Не сочтите за оправдание. Я действительно небольшой опыт в написании имею, поэтому какие-то аспекты в силу "неопытности" могу упускать. Критика же невероятно помогает в написании следующих статей, стараюсь уделять больше внимания деталям. Очень стараюсь улучшать материал, Вам ещё раз больше спасибо!
Kahelman
18.07.2025 13:36Поддерживаю предыдущего оратора, в общем и целом, автор сравнивает яблоки и апельсины.
По поводу скорости исполнения думаю это не критичный момент - если нужна скорость пишите специализированную программу на компилируемых языках.
Для целей автоматизации задач - bash удобнее. Хотя синтаксис мог быть и получше (хотя смотря с чем сравнивать, народ на CMD скриптах в винде такое пишет, …)
Главное преимущество bash- это же факто стандарт и нет разницы между версией 2.х и 3.0 как сделали в питоне и миграция заняла сколько лет? Гарантия обратной совместимости классная штука.
Q3_Results
18.07.2025 13:36Запуск скриптов на питоне и запуск скриптов на баше имеет нюансы с точки зрения процессов операционной системы. В том числе в сценариях, когда идёт вызов системных команд из скрипта. Условно, запускается скрипт часть уже работающего процесса или как отдельный процесс. Хотелось бы про эти нюансы узнать в статье
bolk
У «bash и ко» есть интересное достоинство, про которое почему-то все забывают — процессы, связанные через pipe, могут прекрасно утилизировать все ядра. Никакой gil этому не помешает.