Привет, Хабр! В мире автоматизации часто возникает вопрос: писать скрипт на 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с, но с поддержкой:

    1. Пропущенных значений

    2. Разных форматов CSV

    3. Дополнительной аналитики

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 в случаях, когда:

  1. Требуется быстрое решение для одноразовой задачи

  2. Работа с текстовыми потоками и системными утилитами

  3. Необходима максимальная производительность на простых операциях

  4. Скрипт будет выполняться только в Unix-окружении

Выбирать Python, когда:

  1. Требуется сложная логика обработки данных

  2. Важна читаемость кода

  3. Необходима кроссплатформенная совместимость

  4. Предполагается дальнейшее развитие скрипта

  5. Планируется работа со структурированными данными (JSON, XML, CSV)

Со своей же стороны добавлю. Я часто использую "гибридный" подход. Комбинирование языков даёт максимальную эффективность: Bash - для быстрой предобработки данных, Python - для сложного анализа.

P.S. Я веду свою группу в Телеграмм, буду рад видеть всех, кому интересен процесс написания скриптов и автоматизация в мире IT.

Комментарии (29)


  1. bolk
    18.07.2025 13:36

    У «bash и ко» есть интересное достоинство, про которое почему-то все забывают — процессы, связанные через pipe, могут прекрасно утилизировать все ядра. Никакой gil этому не помешает.


  1. apevzner
    18.07.2025 13:36

    Шелловские скрипты становятся очень хрупкими при работе с именами файлов, которые могут содержать пробелы...


  1. skymal4ik
    18.07.2025 13:36

    Избегаю скриптов на баше кроме разве что совсем простых на пару строк) из-за его, bash-a, синтаксиса. Простите за сквернословие, но назвать его могу только ублюдским.

    Массивы, присваивание где нельзя ставить пробел между переменной и равно, все эти ne le ge , циклы - как будто против человечества всё это писалось. Понимаю, что наследие, традиции, ограничения, но прямо раздражает :)


  1. vadimr
    18.07.2025 13:36

    Не очень корректное сравнение. Python никак не мешает использовать сложные командные строки. Поэтому Python является скорее надстройкой над bash, чем альтернативой.


  1. shoytov
    18.07.2025 13:36

    У Python есть один явный минус в сравнении с bash - это виртуальное окружение. Далеко не все скрипты можно "вот так взять и просто написать" без использования сторонних библиотек, а для этого нужно создавать виртуальное окружение, прописывать полный путь к интерпретатору в этом окружении... То есть речи о переносимости "из коробки" тут быть не может.


    1. skymal4ik
      18.07.2025 13:36

      Часть библиотек есть в репозиториях ОС, иногда проще ставить их, чем возиться с виртуальными окружениями. Понятно, что не всё есть и версии старее, но иногда этого достаточно.


      1. shoytov
        18.07.2025 13:36

        нет, дорогой друг, ставить какой-то пакет питона в "стандартное" окружение ОС - это путь в никуда, если вы собираетесь прожить с этой системой хоть пару лет (со всеми обновлениями безопасности и т.д,) Никогда! Повторю, НИКОГДА, не нужно ставить какие-то пакеты в окружение python вашего дистрибутива. Нет, я не выпендриваюсь, честно, просто это - опыт.
        P.S. python - мой рабочий инструмент более 10 лет, я его искренне люблю и лелею, но нет - для задач переносимой автоматизации он подходит едва ли...


        1. seepeeyou
          18.07.2025 13:36

          Какие-то пояснения будут, почему?


          1. shoytov
            18.07.2025 13:36

            Не зря это считается бэд практис. Самый простейший пример: нужен какой-то пакет не ниже какой-то версии, а этот пакет уже установлен для системных нужд, а ты взял и обновил этот пакет и все, в системе что-то сломал


        1. jingvar
          18.07.2025 13:36

          Расскажите это ансиблу и солту :)


          1. shoytov
            18.07.2025 13:36

            А тут подробности нужны, я, как искренний любитель Ansible, не сталкивался с какими-то трудностями


    1. Exinker
      18.07.2025 13:36

      В чем проблема при установки утилиты создать окружение, указывать до него относительный путь, добавлять symlinks и прочее?


      1. shoytov
        18.07.2025 13:36

        ну тут go больше python уже подойдет, чтобы меньше телодвижений было. Дело, конечно, каждого, как извращаться. Как говорится "можно и зайца научить курить, но нафига?". Так и тут: bash - понятный POSIX инструмент, здесть P (Portable) является ключевым. Для каждой задачи должен подходить свой инструмент. Если задача требует программирования, то надо смотреть на накладные расходы. Никогда нет супер правильного решения - есть только компромиссы, с которыми мы готовы мириться


    1. vadimr
      18.07.2025 13:36

      Если задачу можно решить на голом баше, то на питоне без сторонних библиотек тем более можно.


      1. 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`


        1. vadimr
          18.07.2025 13:36

          Так вам и в питоне никто не мешает так же написать:

          os.system("awk '{for(i=1;i<=NF-2;i++) print $i}' /proc/loadavg | sort -nr")


          1. shoytov
            18.07.2025 13:36

            да если делать вызов системных утилит - какой смысл использовать что-то другое) как я уже писал в другом комментарии выше - все можно сделать как угодно, все это будет компромисс, как хочется так и делай


            1. vadimr
              18.07.2025 13:36

              Смысл в том, что не всё можно сделать системными утилитами (или, по крайней мере, не всё легко сделать).


  1. LexD1
    18.07.2025 13:36

    Bash — командная оболочка (UNIX, GNU/Linux, MacOS).

    Python — высокоуровневый язык программирования.

    Сравнение кажется мне не особо корректным. Разным задачам — разные инструменты.

    P.S. Но заголовки в стиле "versus" нравятся, хоть и маркетинг.

    P.P.S. «Bash vs Golang» # ?


    1. Darkholme
      18.07.2025 13:36

      А если предположить, что вы работаете с автоматизацией в Linux, и у вас из инструментов как раз bash и python? И задачи как раз не сверхсложные, но далеко не всегда простые. Спасибо, на парсить YAML/JSON на bash я желанием не горю, да и в некоторых местах без Python никуда (например, модули к системам автоматизации)


      1. Kahelman
        18.07.2025 13:36

        Для Парсинга json сузествует jq, для Yaml -awk, кстати писат на нем гораздо проце чем на питоне.
        Чтобы скрипты не превращались в трудно поддерживаемую мешанину - пишите Makefile-в которые позволяют легко структурировать скрипты.


        1. tentakle
          18.07.2025 13:36

          для Yaml -awk

          yq есть.


    1. eternaladm Автор
      18.07.2025 13:36

      Спасибо за комментарий! Если рассматривать с подобной стороны - определенно факт. Я же хотел сравнить использование под те или иные задачи на Linux. Фактически, все задачи можно решить на одном bash, не городить окружения и тд, но ведь с точки зрения удобства подходы будут отличаться.


  1. Ninil
    18.07.2025 13:36

    Согласен с предыдущем коментарием.
    ПыСы

    • уже было на хабре

    • по всей видимости эффект от чатаЖПТ и иже с ними + "эффект ваАйТишников" уже провел к тому, что появилось много людей, не видящих абсурдности тем, подобных теме этой статьи.


    1. eternaladm Автор
      18.07.2025 13:36

      Спасибо за комментарий!

      уже было на Хабр

      Попробуйте найти через поисковик статьи, например, «о пользе высшего в IT». Вы будете крайне удивлены их количеству. Это касается в целом большинства тем.

      по всей видимости эффект от чатаЖПТ и иже с ними + "эффект ваАйТишников"

      Раскройте понятия, пожалуйста. Не понимаю, что за «эффекты».


  1. andrey0700
    18.07.2025 13:36

    К статье есть много замечаний.

    1. Не нашёл описания методологии выполнения тестирования. Как замерялось время (timeit в Python, time в Bash?), сколько проходов каждого теста использовалось для усреднения результатов? Использовались ли одни и те же файлы, либо же каждый раз создавались новые?

    2. Воспроизводимость. Куски кода, это хорошо, но желательно ещё добавить ссылку на репозиторий с проектом тестирования, чтобы любой желающий мог проверить результаты через автоматизированный скрипт работающий с создаваемой на лету tmpfs. Скажем так, те, кто ходил по врачам и знакомы с понятием доказательной медицины (включая такие понятия как предвзятость), скорее всего пройдут мимо этой статьи, пролистав её до конца.

    3. Путаница в терминологии. Вы сравниваете не Bash и Python, а библиотеки Python и команды UNIX-подобных систем. Они никакого отношения непосредственно к языкам не имеют. Например, Awk — это вполне самостоятельный парсер, который ничего не мешает вызывать напрямую из Python минуя командный интерпретатор. А pandas в Python не входит, в Python входит модуль csv.

    4. Неправильно подобранные решения/алгоритмы для сравнения. При анализе логов в Python используется медленная регулярка, а в Bash — нет. Самым примитивным решением в Python будет split() для разделения на колонки, а не регулярки. В случае сокетов и использования disk_usage из shlibs вообще не должно быть сильно большой разницы между языками, как мне кажется. Там всё будет зависеть больше от скорости работы системных вызовов и работы почтового сервера (в том числе всевозможных задержек). Поэтому сразу возникает вопрос, а что тут замерялось-то со стороны языков? А если скрипт многократно запускался, то у Python инициализация самого интерпретатора и модулей в разы медленнее, чем у Bash (см. ниже).

    5. Собственно, инициализация интерпретатора в Bash намного быстрее, чем в Python. Но это касается лишь инициализации, а не длительной работы скрипта. То есть многократный запуск маленького быстрого скрипта на Python будет медленнее, чем на Bash. Это учитывалось? В статье эта информация должна быть отражена, поскольку может оказывать значительное влияние на само тестирование, искажая его результаты.


    1. eternaladm Автор
      18.07.2025 13:36

      Спасибо аз комментарий! Обратная связь очень помогает делать материалы более качественным.

      1. Ваше замечание полностью справедливо, стоило внести эту информацию в статью. Для Python использоваться timet, для Bash - time. Проходов было 3, файлы же использовались одни и те же.

      2. Момент с созданием репозитория рассмотрю в обязательном порядке, данный пункт действительно был упущен.

      3. Что касательно путаницы в терминологии... Вы правы, фактически я противопоставлял 2 разных подхода. Методологическая ошибка, которая может ввести в заблуждение.

      4. Да, мой пример с регулярками для разбора логов в Pythn - не самый лучший выбор для демонстрации производительности, были примеры более корректные. Но в этом аспекте я сознательно пошёл на компромисс в пользу "универсальности", тк регулярки лучше справятся с "грязными" данными. В статье данный момент действительно стоило оговорить, дабы не вводить в заблуждение.

      5. И, про инициализацию интерпретатора - это наиболее важное замечание, которое мной было вообще упущено из виду. Разница в скорости запуска может быть критичной для каких-то сценариев.

      Спасибо! Вы указали на все слабые места в статье, со всем согласен. Критика бесценна. Не сочтите за оправдание. Я действительно небольшой опыт в написании имею, поэтому какие-то аспекты в силу "неопытности" могу упускать. Критика же невероятно помогает в написании следующих статей, стараюсь уделять больше внимания деталям. Очень стараюсь улучшать материал, Вам ещё раз больше спасибо!


    1. Kahelman
      18.07.2025 13:36

      Поддерживаю предыдущего оратора, в общем и целом, автор сравнивает яблоки и апельсины.

      По поводу скорости исполнения думаю это не критичный момент - если нужна скорость пишите специализированную программу на компилируемых языках.

      Для целей автоматизации задач - bash удобнее. Хотя синтаксис мог быть и получше (хотя смотря с чем сравнивать, народ на CMD скриптах в винде такое пишет, …)

      Главное преимущество bash- это же факто стандарт и нет разницы между версией 2.х и 3.0 как сделали в питоне и миграция заняла сколько лет? Гарантия обратной совместимости классная штука.


  1. Q3_Results
    18.07.2025 13:36

    Запуск скриптов на питоне и запуск скриптов на баше имеет нюансы с точки зрения процессов операционной системы. В том числе в сценариях, когда идёт вызов системных команд из скрипта. Условно, запускается скрипт часть уже работающего процесса или как отдельный процесс. Хотелось бы про эти нюансы узнать в статье