Ця стаття призначена для пітонерів, що починають знайомство з Linux. Часто виникає потреба автоматизувати деякі операції, а з цим добре справляються утиліти командного рядка. Але що робити, якщо не хочеться використовувати незвичний bash? Не треба засмучуватися, ми можемо використовувати улюблений Python. В цій статті ми напишемо утиліту, що буде працювати аналогічно стандартним утилітам (такими як cat
чи grep
).
Написання скрипту
Ми використовуватимемо Python 3. Давайте напишемо простий скрипт, що буде виводити текст, який передасть користувач (аналог echo
). Перш за все, потрібно якось цей текст отримати. Цей процес називається парсингом (або розбором) аргументів. В Python для цього є два основні інструменти:
Масив sys.argv
Цей масив зберігає все, що було написано в командному рядку, включаючи назву нашого файлу.
➜ python3 print_argv.py hello codeguida
['print_argv.py', 'hello', 'codeguida']
Розбір цього масиву напряму підходить лише для дуже простих або дуже специфічних додатків, для решти вистачить модулю argparse
.
Модуль argparse
Цей модуль бере на себе всю роботу по розбору аргументів, їх валідації та генерації повідомлення-довідки. Це дуже потужній модуль, і він входить в стандартну бібліотеку Python. Саме його ми й будемо використовувати.
Напишемо базовий приклад
import argparse
parser = argparse.ArgumentParser(description='My simple echo') # Ініціалізація
parser.add_argument('text', help='Main text to print') # Оголошення
args = parser.parse_args() # Розбір
to_print = args.text
print(to_print)
Тут ми імпортуємо модуль, створюємо екземпляр ArgumentParser
і оголошуємо які аргументи приймає наша програма. В даному прикладі ми оголосили позиційний аргумент, бібліотека також дозволяє обробляти ключові аргументи (--text Python
) та прапорці (--enable-png-support
). Потім ми проводимо сам розбір і отримуємо об'єкт, що зберігає в собі вже валідні аргументи.
Ви можете запустити його і переконатися, що все працює:
➜ python3 myecho.py "Hello, Codeguida"
Hello, Codeguida
➜ python3 myecho.py
usage: myecho.py [-h] text
myecho.py: error: too few arguments
Давайте трохи ускладнимо нашу утиліту і дозволимо окремо задавати текст, що буде відображений до і після основного. Ось тут нам і знадобляться ключові аргументи. Ми введемо нові параметри --before
та --after
, а також задамо для них короткі імена -b
та -a
.
import argparse
parser = argparse.ArgumentParser(description='My simple echo') # Ініціалізація
# Оголошення
parser.add_argument('text', help='Main text to print')
parser.add_argument('--before', '-b', help='Text before', default='')
parser.add_argument('--after', '-a', help='Text after', default='')
args = parser.parse_args() # Розбір
to_print = args.before + args.text + args.after
print(to_print)
argparse
бере на себе багато брудної роботи, вам лишається лише вказати що ви хочете отримати, а він подбає щоб все було як потрібно. Також давайте додамо опцію --critical
, що буде друкувати текст червоним кольором.
import argparse
parser = argparse.ArgumentParser(description='My simple echo') # Ініціалізація
# Оголошення
parser.add_argument('text', help='Main text to print')
parser.add_argument('--before', '-b', help='Text before', default='')
parser.add_argument('--after', '-a', help='Text after', default='')
parser.add_argument('--critical', help='Display text as critical', action='store_true')
args = parser.parse_args() # Розбір
to_print = args.before + args.text + args.after
if args.critical:
to_print = '\\x1b[31m' + to_print + '\\x1b[39m'
print(to_print)
Щоб відобразити текст червоним кольором ми використовуємо ANSI escape code
, але це лише для демонстрації. Якщо ви захочете пофарбувати ваш текст в Python — користуйтеся спеціальними модулями (наприклад, colorama).
Додання шебангу
Шебанг — це перша стрічка в файлі, що починається з #!
і вказує шеллу за допомогою чого слід запускати цей скрипт. Наприклад, для своїх утиліт на пітоні я використовую такий шебанг:
#!/usr/bin/env python3
На відміну від такого такого:
#!/usr/bin/python3
Мій буде працювати й на тих системах, де пітон встановлено в нестандартну локацію. Я рекомендую додавати шебанг до всіх ваших скриптів. Після додання шебангу слід вказати системі, що наш скрипт не просто файл, а файл, який можна запустити. Зробити це можна або в файловому менеджері (Властивості файлу > Дозволи > Дозволити виконання) або в командному рядку. Також давайте приберемо у файла розширення, щоб не набирати кожен раз три зайві літери:
mv myecho.py myecho
chmod +x myecho
Тепер наш файл можна запускати так:
./myecho Wow
./
на початку команди вказує нашому шеллу, що утиліту слід шукати в поточній директорії. На даний момент наш скрипт недоступний глобально, а лише з поточної папки. Щоб шелл зміг знайти нашу утиліту, слід розмістити її в директорії, що вказана в змінній PATH
. Отримати зміст цієї змінної можна набравши в терміналі echo $PATH
➜ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
Ви можете скопіювати наш файл до будь-якої з цих директорій, але я рекомендую зробити інакше. Краще створити приховану папку в домашньому каталозі та додати її до PATH
. З таким підходом вам не потрібно буде діяти від root'а, а утиліти буде легше організовувати.
mkdir ~/.scripts
mv myecho ~/.scripts/
Тепер слід додати її до змінної PATH
. Для цього відкрийте файл ~/.bashrc
(якщо відсутній — створіть) і допишіть в кінець ось це:
export PATH="<повний шлях до папки>:$PATH" # Наприклад, /home/oleg/.scripts
Лишилося лише перезапустити термінал (або виконати source ~/.bashrc
), і ваша утиліта буде доступна глобально:
source ~/.bashrc
myecho "I love Codeguida, Python, and Linux"
Повний код нашої утиліти:
#!/usr/bin/env python3
#-*- coding: UTF-8 -*-
import argparse
parser = argparse.ArgumentParser(description='My simple echo') # Ініціалізація
# Оголошення
parser.add_argument('text', help="Main text to print")
parser.add_argument('--before', '-b', help='Text before', default='')
parser.add_argument('--after', '-a', help='Text after', default='')
parser.add_argument('--critical', help='Display text as critical', action="store_true")
args = parser.parse_args() # Розбір
to_print = args.before + args.text + args.after
if args.critical:
to_print = '\\x1b[31m' + to_print + '\\x1b[39m'
print(to_print)
Ще немає коментарів