Защо да се работи в конзолата е така приятно? Така е замислено от бащите-основатели на Unix

46
2706

Unix. Легендарната операционна система, която оказа огромно влияние на разработката на всичкия софтуер и на информатиката като цяло. От нея израснаха цели семейства Unix-подобни операционни системи, които всички ние използваме.

Езикът за програмиране C, Ричард Столман и GNU, Open Source движението, Линус Торвалдс с Linux ядрото, маковете, айфоните и Android. Почти всичко в системното програмиране от 21-ви век може да бъде проследено до неговите основи, а това е именно Unix.

Unix се счита за фундаментална база. Но какво толкова е особеното в нея? Това е една интересна тайна. Всъщност тайните са две.

Философията на Unix

Две са основните причини, поради които Unix има такъв успех и се разпространи в целия свят. Първо, тази операционна система е написана на езика от високо ниво С, които я прави мултиплатформена. Тя може да бъде инсталирана на всякакви компютри и адаптирана за компютърни системи с най-разнообразни специфични изисквания. Преди това операционните системи са писани на асемблер за конкретния процесор и конкретния компютър.

Второ, това е правилната операционна система. Тя е създадена в съответствие с набор от общи принципи, съответстващи на цялата философия на Unix.

Браян Керигън (Brian W. Kernighan) и Роб Пайк (Rob Pike) в книгата „Програмната среда на Unix“ (The Unix Programming Environment) формулират основната идея на тази философия по следния начин:

„Ефективността на Unix се определя от използването на един общ подход към програмирането и от философията за използване на компютъра. За да се опише тази философия, едно изречение е съвсем недостатъчно, но ето каква е нейната основна идея – мощността на операционната система до голяма степен се определя от взаимодействието на нейните програми, а не от тяхното наличие и техния брой“.

Редица Unix програми сами по себе си изпълняват съвсем тривиални задачи, но когато се обединят с другите се образува пълен и полезен инструментариум.

С други думи, Философията на Unix е взаимодействието на програмите. Счита се, че програмите на Unix са нещо като строителни тухли, които могат да бъдат комбинирани и по този начин да бъдат създавани изключително ефективни конструкции. Изходът на едната програма е вход за друга програма и по този начин се образува своеобразен конвейер (пайп).

Програмите и командите се съчетават в един общ конвейер не само чрез стандартните и очевидни начини. Има и съвсем нетривиални съчетания.

Вълшебните конвейери

Тази магия е по-лесно да се разбере с помощта на конкретни примери, подбрани от най-популярните автори.

Списъкът на лидерите според броя на кòмитите

Да започнем с един съвсем лесен пример: да се покаже списъка от автори на git хранилище, подредени според броя на кòмитите. Задачата се оказва съвсем лесна, когато се използват конвейери. Извеждаме логовете на комитите с командата git log. Опцията –format=<format> дава възможност да укажем в какъв формат да бъдат комитите. Конкретно в нашия случай опцията –format=’%an’ извежда само имената на авторите за всеки комит.

$ git log --format='%an'

Alice
Bob
Denise
Denise
Candice
Denise
Alice
Alice
Alice

Сега помощната програма sort ще го сортира по азбучен ред:

$ git log --format='%an' | sort

Alice
Alice
Alice
Alice
Bob
Candice
Denise
Denise
Denise

След това използваме uniq:

$ git log --format='%an' | sort | uniq -c

    4 Alice
    1 Bob
    1 Candice
    3 Denise

Според man страницата на uniq, тази програма работи само със съседните съвпадащи редове. Ето защо първоначално този списък трябваше да бъде подреден по азбучен ред. Остана само да променим начина на подреждане – според първото число. За тази цел ще използваме флага -n:

$ git log --format='%an' | sort | uniq -c | sort -nr

    4 Alice
    3 Denise
    1 Candice
    1 Bob

Флагът -r показва, че подреждането ще става в обратен ред. Това е всичко. Сега имаме списъка с авторите на git хранилище, подреден според броя комити.

Преглед на мемовете от /r/memes и слагане на тапети от /r/earthporn

Знаете ли, че може да се добави “.json” към всеки URL на Reddit, за да се получи изходен резултат с JSON формат вместо обикновен HTML? Това открива един съвсем нов свят от възможности! Рака например, прегледът на мемовете може да стане директно от командния ред. Е, не съвсем, понеже изображението ще бъде показано от графична програма, но все пак ще бъде в конзолата. Можем директно да изтеглим файла с помощта на curl или wget по следния начин – https://reddit.com/r/memes.json. Нека се спрем по-подробно:

$ wget -O - -q 'https://reddit.com/r/memes.json'

'{"kind": "Listing", "data": {"modhash": "xyloiccqgm649f320569f4efb427cdcbd89e68aeceeda8fe1a", "dist": 27, "children":
[{"kind": "t3", "data": {"approved_at_utc": null, "subreddit": "memes",
"selftext": "More info available at....'
...
...

Wget приема опцията -O, която указва за запис на файл. А опцията -q показва, че трябва да се работи в „тих“ режим, без на екрана да излиза информацията за статута на изтеглянето. Сега вече разполагаме с една голяма JSON структура. За да можем да анализираме и смислено да използваме тези данни от командния ред, можем да използваме помощната програма jq, която е аналог на sed/awk за JSON. Нейното използване е съвсем лесно и интуитивно.

JSON отговорът изглежда по следния начин:

{
    "kind": "Listing",
    "data": {
        "modhash": "awe40m26lde06517c260e2071117e208f8c9b5b29e1da12bf7",
        "dist": 27,
        "children": [],
        "after": "t3_gi892x",
        "before": null
    }
}

И така, тук виждаме типа Listing и масива children. Всеки елемент от този масив е отделен пост.

Ето как изглежда един от елементите на масива:

{
    "kind": "t3",
    "data": {
        "subreddit": "memes",
        "selftext": "",
        "created": 1589309289,
        "author_fullname": "t2_4amm4a5w",
        "gilded": 0,
        "title": "Its hard to argue with his assessment",
        "subreddit_name_prefixed": "r/memes",
        "downs": 0,
        "hide_score": false,
        "name": "t3_gi8wkj",
        "quarantine": false,
        "permalink": "/r/memes/comments/gi8wkj/its_hard_to_argue_with_his_assessment/",
        "url": "https://i.redd.it/6vi05eobdby41.jpg",
        "upvote_ratio": 0.93,
        "subreddit_type": "public",
        "ups": 11367,
        "total_awards_received": 0,
        "score": 11367,
        "author_premium": false,
        "thumbnail": "https://b.thumbs.redditmedia.com/QZt8_SBJDdKLVnXK8P4Wr_02ALEhGoGFEeNhpsyIfvw.jpg",
        "gildings": {},
        "post_hint": "image",

        ".................."
        "Тук има още много редове"
        ".................."
    }
}

Виждаме голям брой изключително интересни атрибути, включително URL на изображенията-мемове.

Съвсем лесно можем да получим списъка на всички URL постове:

$ wget -O - -q reddit.com/r/memes.json | jq '.data.children[] |.data.url'

"https://www.reddit.com/r/memes/comments/g9w9bv/join_the_unofficial_redditmc_minecraft_server_at/"
"https://www.reddit.com/r/memes/comments/ggsomm/10_million_subscriber_event/"
"https://i.imgur.com/KpwIuSO.png"
"https://i.redd.it/ey1f7ksrtay41.jpg"
"https://i.redd.it/is3cckgbeby41.png"
"https://i.redd.it/4pfwbtqsaby41.jpg"
...
...

Първите два линка трябва да се игнорират, понеже са стандартните закачени постове на модераторите.

Помощната програма jq прочита данните от стандартния вход и получава същия JSON, който видяхме по-горе. След това е указан масивът с постовете .data.children. Синтаксисът .data.children[] | .data.url означава „премини през всеки елемент от този масив и изведи url полето, което се намира в полето data на всеки елемент“.

По този начин получаваме списък с URL на всички топ-мемове в поддиректорията  /r/memes към този момент. Ако искате да прегледате най-добрите постове за седмицата, то трябва да използвате:

https://reddit.com/r/memes/top.json?t=week

А ако искате да видите топ-мемовете на всички времена, трябва да използвате опцията t=all, за година: t=year и т.н.

След като вече имаме списък с всички URL, той може да бъде подаден към xargs. Това е една наистина полезна помощна програма за създаването на сложни командни редове от стандартния вход. В нейното описание можем да видим следното:

„Командата xargs обединява определен набор от зададени в командния ред начални аргументи, прочетени от стандартния вход, като може да изпълни така получената команда един или няколко пъти“.

Празните редове се игнорират.

Тоест, конзолната команда:

$ echo "https://i.redd.it/4pfwbtqsaby41.jpg" | xargs wget -O meme.jpg -q

е еквивалентна на следната:

$ wget -O meme.jpg -q "https://i.redd.it/4pfwbtqsaby41.jpg"

Сега вече е възможно просто да се подаде списъка с URL-те към малката програма за преглед на изображения feh или eog,които приемат URL в качеството на допустим аргумент:

$ wget -O - -q reddit.com/r/memes.json | jq '.data.children[] |.data.url' | xargs feh

След това стартираме feh с мемовете, като можем да използваме стрелките за навигация, сякаш тези изображения са записани в локалния диск на нашия компютър.

А може и всичките изображения да бъдат изтеглени с помощта на wget чрез замяната на feh с wget в реда по-горе.

Възможностите на този подход са на практика безгранични. Има и друг вариант за използване на изображенията от Reddit чрез JSON – използването на топ-изображението от поддиректорията  /r/earthporn като тапет за десктопа:

$ wget -O - -q reddit.com/r/earthporn.json | jq '.data.children[] |.data.url' | head -1 | xargs feh --bg-fill

А ако искате, можете да зададете cron процес, който да се изпълнява на всеки един час.

Гора в Нидерландия [2000×1333]

Гренландия [4032×3024]

Разбира се, вместо /r/earthporn могат да се вземат изображенията от други поддиректории на Reddit.

Ето в това е силата на конвейерната обработка на Unix. Един единствен ред в конзолата прави всичко: изтегля JSON файл, анализира го, намира необходимите данни, след това изтегля изображението от съответния URL и го поставя като тапет на работния плот.

Дотук това бяха само няколко случайни примера. В реалността е възможно да се направят изключително много неща с помощта на едноредова команда в конзолата, която изгражда конвейер от съвсем малки и опростени помощни програми.

Работата, която доставя удоволствие

Философията на Unix е толкова дълбока и фундаментална, че е породила цели класове от Unix-подобни системи, включително BSD, macOS и Linux. Те всичките се базират именно на тази философия. Страничният ефект от работата в подобна среда е чувството, че всичко се върши правилно и точно както трябва. Създава се усещането, че всичко трябва да работи именно така и че това е най-добрият начин да се свърши работата: от малки тухлички, които са базовите строителни блокове, се създават сложни структури –  конвейери с произволна сложност. Това е наистина гениално.

Няколко думи за бащите-основатели

Може би след много години Томпсън и Ричи ще бъдат канонизирани и ще бъдат признати за бащите-основатели на разумния компютърен свят. Но днес цифровите археолози продължават на намират нови факти от историята на Unix.

Някои Unix разработчици са живи и здрави. Ако искате да видите какви операционни системи и програми използват в своите домашни компютри, то можете да посетите галерията от 2002 година, както и от 2015 година.  Всеки от тях е получил електронно писмо, с което е помолен да направи скрийншот на своя текущ десктоп, като се има предвид веднага след като прочетат имейла.

Десктопът на Брайан Керниган от месец октомври 2015 година

Денис Ричи (1941-2011) през 2002 година е използвал доста необичайна инсталация: неговият домашен клиент с NT 4 е включен чрез ISDN към отдалечения сървър с Plan 9 в централния офис на Bell Labs.

Plan 9 е иновационна операционна система, базирана на концепцията за разпределените изчисления. Всеки компютър може да използва произволни ресурси на друга компютърна система като собствени. Сега тази концепция се опитват да реализират във вид на контейнери, виртуални машини и микро онлайн услуги, като всичко се върши на ниво на ядрото.

Десктопът на Брам Моленар (Bram Moolenaar), създателят на мощния текстов редактор Vim.


Можем да продължим по този начин още много, но да се надяваме, че новото поколение от съвременни програмисти и разработчици няма да забрави, че всички ние стоим на раменете на гиганти.

3.3 9 гласа
Оценете статията
Абонирай се
Извести ме за
guest
46 Коментара
стари
нови оценка
Отзиви
Всички коментари