Привет, Хабр! В мире автоматизации часто возникает вопрос: писать скрипт на 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.
Комментарии (9)
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 лет, я его искренне люблю и лелею, но нет - для задач переносимой автоматизации он подходит едва ли...
LexD1
18.07.2025 13:36Bash — командная оболочка (UNIX, GNU/Linux, MacOS).
Python — высокоуровневый язык программирования.
Сравнение кажется мне не особо корректным. Разным задачам — разные инструменты.
P.S. Но заголовки в стиле "versus" нравятся, хоть и маркетинг.
P.P.S. «Bash vs Golang» # ?
Ninil
18.07.2025 13:36Согласен с предыдущем коментарием.
ПыСыуже было на хабре
по всей видимости эффект от чатаЖПТ и иже с ними + "эффект ваАйТишников" уже провел к тому, что появилось много людей, не видящих абсурдности тем, подобных теме этой статьи.
bolk
У «bash и ко» есть интересное достоинство, про которое почему-то все забывают — процессы, связанные через pipe, могут прекрасно утилизировать все ядра. Никакой gil этому не помешает.