What is expected from a scripting language:

  1. can work with files (read/write csv/yaml/json)
  2. can work with the network (send an http request)
  3. make some kind of logic
  4. does not require environment installation and compilation
  5. all in one file

BASH satisfies all of this, but it has its own problems.:

  1. It’s hard to read
  2. It’s hard to debug
  3. It’s hard to write nontrivial logic

It would seem that Python allows you to solve all these problems, but very quickly you want to install some packages on Python.

How can I make it more comfortable?

  1. We put `poetry'.
  2. Create a folder for the script: mkdir my-script-1
  3. Initialize poetry there: cd my-script-1 && poetry init'. Or take the ready-made file myproject.toml`:
[tool.poetry]
package-mode = false

[tool.poetry.dependencies]
python = "^3.12"
pandas = "^2.2.1"
requests = "^2.31.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
  1. Create a file for our script: `touch main.py && chmod +x main.py '
  2. Download the dependencies: poetry install --no-root' (or just poetry installif thepackage-mode=false` property is set)
  3. Go into the virtual environment (from there already you can run the script): poetry shell, or directly run poetry ru ./main.py

The script itself (just a starting example):

#!/usr/bin/env python3

# https://docs.python.org/3/library/dataclasses.html
from dataclasses import dataclass
# https://pandas.pydata.org/
import pandas as pd
# https://requests.readthedocs.io/en/latest/
import requests
from numpy import ndarray


@dataclass
class DocTags:
    id: str
    tags: [str]


def parse_line(values: ndarray) -> [DocTags]:
    assert values.size == 2
    doc_id: str = values[0]
    tags_str: str = values[1]
    tags = list(map(str.strip, tags_str.split(",")))
    return DocTags(doc_id, tags)


def read_file(filename: str) -> [DocTags]:
    data = pd.read_csv(filename, sep="\t", header=None)
    return list(map(parse_line, data.values))


def main():
    docs = read_file("example.tsv")
    for doc in docs:
        with open(f"out/{doc.id}.txt", 'w') as file:
            file.write(str(doc) + "\n")
            response = requests.put(f"https://httpbin.org/anything/{doc.id}", json=doc.tags)
            file.write(f"status_code={response.status_code} json={response.text}\n")


if __name__ == '__main__':
    main()

Естественно, это все открывается в PyCharm: там можно запускать и вставать в отладку.

В итоге, все-таки есть дополнительные шаги, но их не так уж и много.

PS. Домашнее задание: написать то же, но на чистом BASH. У меня получилось 22 строчки, но сложно читаемых и не поддерживаемых. Впрочем, для скриптов это не особо надо. Тем не менее, это заставило задуматься почему изначально все-таки выбрал BASH, а не Python.

PPS. Домашнее задание 2: переписать скрипт так, чтобы внешние библиотеки (pandas и requests не требовались – по идее это должно быть просто). Решение, если писать не хочется.

PPPS. Можно еще то же самое посмотреть на Kotlin (link1, link2), Ruby и других языках.