Можно ли писать скрипты на C++?


    Недавно пришлось мне опять/снова погрузиться в чудесный мир программирования Linux скриптов. В принципе, дело не очень хитрое, но поскольку мне попадаются такие задачи не часто, то каждый раз изучаю заново. Знаю точно, что завтра многое забуду и через месяц опять буду гуглить, как сделать то или это. Проблема еще оказывается в том, что зачастую не пишешь скрипт заново, а модифицируешь существующий, уже написанный кем-то. А он может быть не bash, а sh или еще что-то… Различия в синтаксисе есть, что работает в sh по идее должно работать и в bash, но не всегда наоборот. А если там dash или ash? Я не знаю… Различия в этих скриптовых языках все же есть, и они сбивают с толка. Ну и конечно, лично для меня, вишенка на торте, когда скрипт вызывает какой нибудь sed или awk и там такие параметры в командной строке, что смотришь на них и диву даешься. Понятно, что это все зависит от квалификации программиста, но вот у меня не все в голове помещается. И вот сейчас мое терпение лопнуло и я подумал, что отныне хочу попробовать писать скрипты на c++…

    Я понимаю, что для true системного администратора моя мысль может показаться крамольной. Но почему бы и нет?

    Итак, мысль очень простая. Я хочу писать c++ скрипты так же, как пишутся обычные скрипты, то есть первая строка скрипта должна содержать shebang и указание на путь к «интерпретатору»:

    #!/bin/c++

    Последующие строки скрипта будут просто обычной программой на c++.

    Я должен подготовить «интерпретатор» скрипта c++. Написать его можно на чем угодно, да хоть на bash (это в последний раз, хотя не точно). Конечно он будет не интерпретатором, а компилятором.

    Вот что у меня получилось:

    #!/bin/bash
    
    msg_file=/dev/null
    #msg_file=/dev/stdout
    
    tmp_path=$HOME"/.cache/c++/"
    mkdir -p $tmp_path
    tmp_file=$1".c++"
    exe_file=$1".bin"
    if test $1 -nt  $tmp_path$exe_file; then
        echo "Need to recompile.." > $msg_file
        tail -n +2 $1 > $tmp_path$tmp_file
        eval "g++ -o $tmp_path$exe_file $tmp_path$tmp_file > /dev/null 2>&1"
        if [ $? -eq 0 ]
        then
    	echo "Compiled ok" > $msg_file
        else
    	echo "Compile error" > $msg_file
    	exit 255
        fi
    fi
    eval "$tmp_path$exe_file $@1"
    

    Этот скрипт делает все, что нужно. В качестве временной папки я выбрал папку ~/.cache/c++. В эту папку будет копироваться исходный скрипт, но без первой строки с shebang. Делается это командой tail. Имя нового файла будет как у исходного скрипта, но с расширением c++. В той же самой папке будет собираться бинарник, с расширением .bin. Но, сперва, конечно, делается проверка «if test» на время создания бинарника. Компиляция происходит только если существующий бинарник устарел по времени по отношению к исходному «скрипту». Запускается бинарник командой eval и ему передаются все исходные параметры.

    Этот Файл c++ нужно скопировать в папку /bin и сделать его исполняемым (chmod a+x).

    Попробую написать свой первый «c++ скрипт»:

    #!/bin/c++
    
    #include <stdio.h>
    #include <iostream>
    
    using namespace std;
    
    int main( int argc, char *argv[] )
    {
        cout << "hello world!\n";
        for( int i=0; i<argc; i++)
        {
    	cout << "Param" << i <<  " is " << argv[i] << "\n";
        }
        return 60+argc;
    }
    

    Эта программа просто печатает список входных параметров и возвращает их количество + 60.
    Запускаю мой «скрипт»:



    Работает!!!

    Если сделать в c++ коде ошибку, то программа не запустится, так как не скомпилируется, но echo $? вернет 255. Но так и задумано было.

    Использование c++ дает громадные возможности. Во-первых, привычный синтаксис. Во-вторых, стандартные классы вроде std::vector, std::map или std::string и другие — незаменимые вещи. Та же строка — что хочешь с ней делай, ищи в строке, разбивай на подстроки, разъединяй и властвуй, получай массивы. И не нужны мне ни sed ни awk. В-третьих, отладчик — господи! какое счастье! у меня для скрипта есть отладчик gdb! Дальше, можно использовать std::filesystem (если компилятор позволяет). Можно продолжать…

    К сожалению, у меня часто бывает, что сперва сделаю, а потом подумаю: «а вдруг кто-то такое уже сделал?». И в самом деле, я оказывается далеко не первый, кто придумал делать так же. Вот пример: https://github.com/dimgel/cpp-linux-scripts идея та же, реализация другая. Потом оказалось, что есть и другие реализации.

    В общем, испытал небольшое разочарование в собственной неисключительности. Однако, поискал по Хабру — похожего не нашел. Может кому-то покажется хотя бы любопытным?
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 73

      +7

      CERN использует cling (до этого был cint ). Для Си есть tcc с параметром -run

        +1
        а ещё есть csh, который, с одной стороны, полноценный шел, а с другой — в качестве языка в нем С
        +22
        Можно ли писать скрипты на C++

        Конечно можно, но зачем? Мне думается, что правильнее подбирать инструмент под задачу, а не задачу под инструмент. Для скриптинга у C++ слишком многословный и сложный синтаксис, а также относительно бедная стандартная библиотека.


        Для этой задачи гораздо лучше подходит Python и компилировать ничего не надо. Добавить shebang #!/usr/bin/env python3 и запускать прямо из bash. И все возможности stdlib (pathlib, sys, os, shutil, re, argparse, ...) к вашим услугам. А если чего-то не хватает, pip install --user ... и погнали.

          +3

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

          +5
          вроде std::vector, std::map или std::string т другие
          std::filesystem (если компилятор позволяет)

          конечно забавно скриптовать на C++, но в чем профит — непонятно. Скорости разработки оно не добавляет в сравнении с каким-нибудь питоном, пляски вокруг utf, стандартные контейнеры и filesystem крайне сомнительный профит. Быстрого подключения модулей нет ибо надо прокидывать все это дело компилятору. Предлагаю добавить хаб "ненормальное программирование"

            –4
            Да, возможно это ненормальное программирование. Но насчет скорости, когда bash скрипт запускает из себя множество других процессов типа ls, sed, awk и прочие — а потом ждет их вывода для анализа — это что быстро работает?
              +9
              да :) их (утилиты) шлифовали десятилетиями и они действительно быстро работают.

              Ну и речь шла, опять же, про скорость разработки, а не исполнения скрипта.
                +2
                Вот буквально только что почитал обсуждение тормозов rm, старейшей утилиты, 'шлифованной десятилетиями'
                <сарказм>
                +1
                Для таких придумали демоны типа speedy, которые второй раз не запускают утилиту.
                  +2

                  Поверьте, очень быстро

                    –2
                    Вот все хорошо в консольных утилитах, но до сих пор все они однопоточные. Это во времена когда за 10 лет в процессорах в однопотоке прибавились 30%.
                    Не видно даже подвижек чтобы хотя бы пакетные менеджеры использовали много потоков. Хотя бы для распаковки. И так во всем.
                      0

                      Ест чудная обёртка apt-fast правда она только качает в многопотоке

                        +1
                        Рискованно производить установку во много потоков — потом можно не несколько дней потратить на восстановление системы. А многопоточная закачка давно есть в том же YUM/DNF.

                        А что касается многопоточной работы базовых утилит, не забываем, что работают они с ПОТОКАМИ. То есть каждой скармливается поток, с которым она что-то должна сделать. Если нужно делать что-то в несколько потоков, просто запускаете эти несколько потоков и не маетесь с последовательным запуском. Я так и делаю, причём, во всё том же Bash.
                          +1

                          Установку не надо, а скачивание и распаковку — да. Все что может быть безопасно распараллелено.

                            0
                            Вот распаковку пока не видел. Хотя, может быть, она и происходит. Надо будет проверить, как приедут очередные обновления. С другой стороны, это требует много места, а оно не всегда есть. Это ещё и вопрос работоспособности системы в процессе установки пакетов: если слишком сильно загрузить файловую систему, работа остальной системы может остановиться. А ведь это не всегда мощный игровой компьютер.
                              0

                              Можно добавить опцию. Но пока всех устраивает скачивание за 5 минут вместо 1 и распаковку 10 вместо 2.

                                0
                                DNF качает во столько потоков, во сколько можно, чтобы не забивать канал окончательно и чтобы данные успевали приходить. То есть, если скорость закачки в три потока такая же, как в два, то стоит остановиться на двух, потому что три потока будут лишь впустую грузить процессор. А учитывая служебный трафик, увеличение количества потоков может даже замедлить процесс. А вот про распаковку параллельным потоком стоит подумать. Не удивлюсь, если это уже реализовано.

                                P.S. На моей машине и на моей сети закачка идёт в два потока. Хотя и не всегда. Видимо, зависит от загруженности сети и отдающего сервера.
                          +2

                          У xargs есть отличный аргумент -P, который как раз и запускает несколько процессов параллельно. Не многопоточность, но загрузить проц до упора вполне можно. Например, для кодирования больших объёмов текста с помощью Sentencepiece или преобразования FB2 ⇒ TXT.

                            +1

                            Тогда уж можно сразу GNU Parallel вспомнить.

                              +1

                              Можно, но xargs более вероятно будет установлен из коробки. Например, в дебиане он входит в findutils вместе с find (странная группировка, по-моему).

                        +2
                        это что быстро работает?

                        Очень быстро, да. Но эксперимента ради предложил бы переписать утилиту yes из набора coreutils собственными силами и потом помериться в скорости. Там же голые Си под низом, которые отлаживали со второй половины прошлого века. В последней декаде решили еще бустануть, переписав на раст и сделав чуть более человечные API, кроссплатформенность и всякое разное прикольное (см. ripgrep, exa ). Но как упоминалось ниже — речь не про скорость работы, а про скорость разработки. Едва ли с быстренько можно написать какое-нибудь префиксное дерево чтобы вместо grep/sed использовать. Прототипировать может быть удобно, если из консоли не вылазить, но я обычно для такого использую sublime text с настроенной командой для REPL, а то и вовсе использую какой-нибудь wandbox.org или ideone.com. Так что это не та ситуация когда строгая типизация и манипулирование байтами имеет хоть сколько-нибудь значимое преимущество.
                        Второй нюанс — это все же не скриптование, а именно перекомпиляция, т.к. для полноценного скриптования нужен интерпретатор, вроде вышеупомянутого cling. Такое скриптование далеко не факт что работает сильно быстрее питона, если вообще быстрее.

                          +3

                          Ну, например, я всякие логи паршу совсем не awk’ом, а работает оно быстрее, выглядит поддерживаемее, да и скрипт пишется быстрее, чем у шарящего в awk коллеги.


                          Кстати, как раз завтра выложу статью про борьбу с wc в скорости.

                            0
                            Так-то оно, может и так, но прочтите статью внимательнее: автор в Linux ходит что-то вроде раз в месяц и ненадолго. То есть он каждый раз всё гуглит и изучает заново, о чём и написал, кстати. То есть для человека, который в *nix не живёт, но постоянно программирует на C++, это будет серьёзным ускорением работы. Собственно, я сам, используя Linux уже больше 20 лет, так и не осилил разобраться с awk, потому что быстрее построить этажерку из других утилит или перейти на другой язык. Возможно, зря не изучил, но пока нет повода закапываться ещё и в это. sed и тот использую исключительно как обработчик регулярных выражений, хотя знаю, что его возможности гораздо шире. Потому что, если припрёт, к моим услугам Python, на котором я, в основном, и работаю последние 7 лет.

                            И про второй момент: Python, если что, тоже компилирует скрипт, хотя результат сохраняет только для подключаемых модулей, так что это противопоставление не совсем корректно. Да, скорость компиляции у Python выше, но, опять же, помним про время разработки и время работы итоговой программы, потому что, как я уже написал, Python сохраняет результат компиляции только для подключаемых модулей, а инструмент автора — именно для основной программы. А библиотеки и так уже скомпилированы.
                              0
                              противопоставление не совсем корректно

                              Если называть питон чисто скриптовым языком — да, но я вроде только про скорость выполнения упоминал. Да и компиляция у питона ленивая. Можно было аналогично в противопоставление nodejs упомянуть. Тот еще медленнее да еще и по памяти прожорливее.
                              Что до sed/awk — для меня это обычно тоже темный лес. Т.к."сварщик я не настоящий" ибо пишу не с под vim в терминале и руки на мышку перекладываю иногда для моих нужд хватает find+grep с парой заученых ключей. Ну, и питон конечно же.

                                0
                                Не уверен, что сейчас ещё остались чисто скриптовые интерпретаторы, потому что проще «день потерять, зато потом за пять минут долететь». Особенно, если сохранять результат компиляции. Разница лишь в том, что питон начинает выполнение сразу, по ходу компиляции, а в варианте C++ надо сначала скомпилировать всю программу целиком.
                                  0
                                  скриптовые интерпретаторы

                                  ванильный луа, насколько мне известно, не компилируется как питон с артефактами (про новое издание не знаю наверняка). У перла и js/nodejs вроде та же история. Многие лиспы. Преобразование в байткод своей внутренней виртуальной машины не считаю.


                                  день потерять, зато потом за пять минут долететь

                                  в такой ситуации обычно имеет смысл завести cmake файл или еще какой-нибудь конфиг сборки, чтобы и в IDE можно было в случае чего кнопкой завести.

                                    0

                                    Разница в том, что питоноскрипт нормально кэширует сборку, а вот поделка автора статьи — кладет исполняемый файл в /tmp, что, конечно, при следующем запуске скрипта приведет к повторной компиляции. А как только автор втащит boost в свой "скрипт" на С++, то "привет, сосед!"


                                    Чтобы сделать компиляцию безопасной там еще кучу вещей надо сделать — писать sha исходного файла программы, обеспечить конкурентность запуска "скрипта" (что будет если мы один "скрипт" очень быстро запустим два раза подряд), обеспечить пересборку бинаря при изменении кода скрипта и прочее-прочее. И, да, проверка по меткам времени — зашквар. Странно, что это все не продумано

                            +4
                            но в чем профит — непонятно.
                            Профит в повторном использовании кода книг Кернигана, Ритчи, Страуструпа & etc.
                              0

                              Как будто что-то хорошее

                            +8
                            Уважаемый автор! С++ замечательный язык, один из моих любимых. Но… для каждой задачи надо использовать подходящий инструмент. Допустим, вам нужно обработать какой-то лог файл размером NN гигабайт, вытащить оттуда значения, сделать с ними какие-то несложные манипуляции, типа расчета средних, максимальных значений, вывода с сортировкой. Тот, кто владеет perl, grep, awk, sort и регулярками может написать и отладить такой скрипт минут за 15-20. Все эти утилиты внутри очень оптимизированны, начиная от буферного чтения, и заканчивая многопоточностью, если это необходимо. Мало того, они будут соединены в пайп, и работать одновременно, прокачивая через себя данные. То есть, многопоточность будет не только внутри них, но даже на уровне скрипта. Это скрипт легко может загрузить (эффективно!) все 8, или больше, сколько там у вас, ядер процессора.

                            Вот сколько вам понадобиться написать и отладить такой скрипт на C++? С оптимизацией на уровне чтения файлов, многопоточностью, и другими специальными вещами?

                            Так что вот вам мой совет. Начните с малого. Освойте, для начала, например, однострочники на perl и обязательно регулярки. Тут, на хабре, были статьи по обоим темам. С перлом даже awk не понадобиться. grep, sort — там всего-то надо знать по паре-тройке ключей у каждого. Ну а если нужно написать код по сложнее, можно взять, например, питон. После опыта на C++ на нем можно начать писать уже через час после знакомства. Можно и perl, но у него все-же довольно инопланетный синтаксис покажется после C++. Поэтому мой выбор — питон. Но это уже на любителя.
                              0
                              Во многом согласен, только с регулярками не могу согласиться…
                              Some people, when confronted with a problem, think
                              “I know, I'll use regular expressions.” Now they have two problems.
                                +1
                                Зря вы так про регулярки :)
                                Я тоже жил и программировал без них лет 20. Когда встречался с ними — они мне казались то китайским языком, то абракадаброй, то магией. Конечно, я заглядывал в документацию, суть примерно была понятна, но… мозг просто отказывался их воспринимать. Просто не понимал, как такое можно использовать.
                                И все-таки не так давно я начал их понимать, использовать и очень этому рад. После некоторой привычки и практики они становятся понятными, и начинаешь ценить всю их мощь. То, что другими средствами выливается в десятки строк запутанного кода, можно записать регуляркой размером в полстрочки.
                                А что касается проблем… ну так на любом языке можно писать плохой код. Не надо писать стоэтажные регулярки, и тогда они будут простыми, понятными и надежными. Это — всего лишь инструмент. Причем очень эффективный инструмент, если применять его правильно и по назначению.
                                Сейчас, даже если я буду писать на том же C++, и увижу задачу, для которой хорошо подходят регулярные выражения — я буду использовать их и на C++.
                                  +1

                                  На самом деле проблем становится не две, а три+. Если не долбить ими что-то небольшое, то нормально, а если начинать заниматься каким-то массовым процессингом — молиться, чтобы движок регулярок был не слизан с перлового PCRE.

                                    +1
                                    PCRE не слизан с перлового RE, это просто Perl Compatible RE, движок там совершенно другой, к перлу не имеющий никакого отношения (там только фичи и синтаксис общие) и, честно говоря, даже очень быстрый, особенно с учётом JIT.

                                    Если вы читали приведённую ссылку, проблема была не в самом движке, а в
                                    ...poorly written regular expression that ended up creating excessive backtracking.

                                    Разумеется, PCRE не даёт гарантий времени выполнения, но всё же чаще всего основной источник проблем — это сами выражения, который пишут «в лоб».

                                    Некоторые другие движки могут давать гарантии и в чём-то могут быть быстрее, но не бесплатно — далеко не всё можно описать в растовском движке или re2 одним выражением или одним его выполнением.
                                      0

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

                                    +1
                                    Желательно чтобы код был не только быстронаписываемым, но еще легкопрочитываемым.
                                    У регулярных выражении длиннее 15 символов проблемы как с первым, так и со вторым.
                                      0
                                      Эм… Вот тут Вы напомнили мне то, с чего я начинал работу в одной конторе: посадили переписывать генератор интерфейса RPC с Java на C#. То есть был генератор, который парсил документацию под интерфейсу и собирал код на Java, а надо было сделать такой же, но чтобы код был на C#. Он тогда только появился, так что wow-эффект у заказчиков только начинался и они страстно хотели именно C#. В общем, посмотрел я на чудовищные регулярки и отсторожно отошёл в сторонку. Потому что они там были за сотню символов длиной. И просто скопировал их в итоговый продукт, меняя только ту часть, которая склеивала код. Написано было, кстати, на Perl, из-за которого меня, новичка в конторе, и посадили за эту работу.
                                        +1
                                        Не переживайте. Любой программист рано или поздно сталкивается с чужими регулярными выражениями и осознает что здесь нужно много времени чтобы понять и поменять
                                  +6
                                  Насчёт оптимизации и отлаженности готовых инструментов полностью согласен, но вот именно отлаживать сами bash скрипты порой очень непросто, и всегда весьма неприятно.
                                    +5
                                    Все эти утилиты внутри очень оптимизированны

                                    По поводу оптимизации некоторых системных утилит, когда смотришь что они делают через strace — страшно становится. Взять хотя бы канонический пример, утилиту /bin/true, занимающую 25 килобайт! Да, я знаю, туда зашит слой совместимости для разных случаев, а так же хелп, но не нужно говорить, что он будет работать быстрее, чем самописный, оптимизированный для частного случая. Вообще, почти весь софт последних 50 лет был вдохновлён законом Мура и работает быстро только потому, что написан давно (под старые слабые процессоры) и делает довольно простые вещи, но то, что какая-то утилита выполняется за 0.5 миллисекунды не значит, что она быстрая, если тоже самое можно сделать за 0.05. Какое это имеет практическое значение? С точки зрения «мне нужно закрыть этот тикет к четвергу» — никакого. Но с точки зрения базовых кирпичиков, из которых строится фундамент, на котором будет стоять огромный небоскрёб кода — это имеет значение, потому что если фундамент гнилой — всё будет медленно и ресурсозатратно, что мы и видим почти во всех современных решениях. Одна утилита выполняет простое действие за 1мс вместо 0.01мс, она используется 50 раз в другой утилите, а та 50 раз в третей, которую вы вызываете из командной строки, в итоге вы имеете 2.5 секунды на отработку скрипта вместо возможных 25 миллисекунд. Собираясь вместе, например в сборке CI, такие утилиты набирают несколько минут, а то и часов, и мы идём пить кофе пока «оно компилируется». Из за того, что что-то занимает 25 килобайт, вместо 8кб при наивной реализации без лишнего функционала или 1кб при удалении clib и прочих неиспользуемых библиотек. Я не говорю про квадратичный рост вычислений, который тоже иногда проскальзывает, почитайте хотя бы что Джоэл пишет про zero terminated strings. Раньше тоже думал, что систему пишут очень умные ребята и у них всё оптимизировано. Они правда очень умные, но во многих местах улучшать не переулучшать, просто никто туда не лезет.
                                      +2

                                      Хочу напомнить про yes

                                        0

                                        Все так, но время и качество разработки тоже учтите! Вот все эти утилиты полировались годами и десятилетиями и вероятность критичных багов в них… стремится к нулю. А вот Ваша персональная имплементация "yes" — с какой попытки Вы ее корректно напишете, учтете все corner-case? Т.е. — несомненно — нужно работу вести в обоих направлениях — и решать более сложные задачи на базе уже существующего фундамента в виде команд, платформ и фреймворков, а также заниматься написанием нового, но с умом, если это оправдано в конкретном случае. А не просто чтоб было. Примеров неудачных программ, созданных только из NIH — масса

                                      +1
                                      Отличная идея. Ещё если ccache добавить, вообще супер будет.
                                        +3
                                        Во-первых, привычный синтаксис.

                                        Это пока вам не нужно часто делать что-то вроде
                                        app | filter1 | filter2 | filter3
                                        или даже банальном
                                        app1 || app2 && app3
                                        замучаетесь с этим на «чистом» C++, да и многословнее гораздо — нечто простое вроде
                                        for x in $(find . -type f); do app $x; done
                                        будет очень ветвисто.
                                          0
                                          А зачем конкретно в этом примере for x in $(find. -type f), если у find (по крайней мере, в GNU coreutils) есть параметр -exec?
                                            0
                                            Чисто для иллюстрации итерации по результатам вывода процесса. Но если это кажется слишком простым — ок, усложним:
                                            for pid in $(ps axuh|awk '{if ($6 > 3000 && $2 > 1) print $2}'); do
                                              kill $pid
                                            done
                                            

                                              0

                                              Вы наизусть помните, в какой колонке ps axuh что лежит?

                                                0

                                                Помнить не обязательно, есть man.

                                                  –1

                                                  Документация на код, которую мы заслужили.

                                                  –1
                                                  Как уже выше ответили — есть man, но когда мне нужно «вот прям щаз» и что-то не вспоминается — я 15 секунд изучаю вывод «ps axu», смотрю колонки, и ещё 45 секунд пишу этот скрипт.

                                                  Если бы я писал универсальный убиватель процессов для сообщества, я бы сделал всё иначе, с документацией, комментариями и даже (может быть) юнит-тестами, но баш ценен тем что можно быстро и просто сделать то что нужно в тот момент когда нужно, а не разворачивать целый проект с техзаданием, спецификациями и изучением рынка.
                                                    +1

                                                    А когда вы читаете чужой скрипт?


                                                    Обычно когда пишут какую-нибудь программу, работающую с каким-то форматом данных, поля в соответствующей структуре данных не называют как как f0, f1, f2, а стараются дать им более осмысленные имена, хотя документация на формат рядом. Как думаете, почему?

                                                      +1
                                                      Мы кажется где-то мы повернули не туда. Речь шла не о какой-то программе, которую пишут для кого-то, а о написании скриптов здесь и сейчас, под конкретную задачу, а также о способах и скорости их написания.

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

                                                      Как я уже отметил выше, если речь о чём-то переиспользуемом — то подход к написанию будет совсем другим, но в этом нет совершенно никакого смысла если проще написать эту самую программу в одну строчку с нуля, особенно если она нужна один раз в год.
                                                0
                                                Не всегда удобно использовать --exec. В скриптах, если есть возможность написать двумя методами следует писать так, как удобно.
                                                  +1
                                                  В этом случае я xargs использую. +1 к понятности.
                                                    0
                                                    Не всегда спасает, но да.
                                                +1

                                                Ну, если базовые "кирпичики" реализует кто-то другой — то все три примера можно будет перенести в C++ чуть ли не 1 в 1. А ваш 4й пример так даже проще получится.

                                                +5

                                                Не говоря про то, что значительная часть скриптовых задач не решается на C++ без тонны кода на C или сторонних либ вроде boost, в этой статье сразу 3 пути по отстрелу ног в современном Linux.
                                                Во-первых свои утилиты без пакетного менеджера класть в /bin довольно плохая идея, т.к. это может привести к конфликтам при обновлении релиза ОС и не только.
                                                Во-вторых скрипт довольно очевидно небезопасный, поэтому выпускать его куда-либо дальше личной однопользовательской машины в таком виде не кажется хорошей идеей.
                                                Ну и наконец на современных ОС в таком виде это в принципе будет нарушать работу ОС:
                                                /usr/bin/c++ исторически принадлежит компилятору c++ (напрямую или через alternatives, зависит от системы). В последнее время /bin — симлинк на /usr/bin, соответственно в этом случае либо сломается скрипт (g++ не сможет его запустить), либо сломается сборка плюсов в сборочных системах, которые по умолчанию вызывают c++ из PATH

                                                  +1
                                                  Насколько я знаю, такая встроенная возможность (с shebang в первой строчке) есть в языке D.
                                                    0
                                                    Знаю точно, что завтра многое забуду и через месяц опять буду гуглить

                                                    Я веду личную базу знаний для всего, что гуглится дольше 15 мин.
                                                      0

                                                      С помощью какого ПО? если удобно и для себя начну вести

                                                        0

                                                        С помощью приватного репозитория в github.

                                                    • UFO just landed and posted this here
                                                        0
                                                        +1. Тоже не понял, зачем здесь stdio.h
                                                        +2
                                                        Живо представил как подключаешь к такому скрипту boost и………
                                                        image
                                                          0
                                                          В общем, испытал небольшое разочарование в собственной неисключительности.
                                                          Хмм… а я наоборот если вижу, что так уже кто-то сделал, думаю, что не так уж и туп раз пошёл по пути по которому уже кто-то сделал и работает :)
                                                            +3

                                                            Может стоит добавить в хабы "ненормальное программирование?" Тогда всё встанет на свои места :)

                                                              0
                                                              Проблема еще оказывается в том, что зачастую не пишешь скрипт заново, а модифицируешь существующий, уже написанный кем-то. А он может быть не bash, а sh или еще что-то… Различия в синтаксисе есть, что работает в sh по идее должно работать и в bash, но не всегда наоборот. А если там dash или ash?

                                                              Отомстим им всем — запилим скрипт на плюсах, пусть удивляютцо ))) Шутю-шутю.
                                                              Вы жалуетесь на сложности с различными оболочками в скриптах, написанных различными другими людьми и как решение предлагаете нестандартный, но хорошо знакомый язык. А как оно решает проблему дебага уже готовых скриптов? Переписыванием их с нуля?
                                                                +1

                                                                "— Всё это истинно. Тем не менее, в одной строчке баш-скрипта всё равно больше духа Unix, чем в десяти тысячах строк кода Си."
                                                                © Master Foo and the Ten Thousand Lines

                                                                  0
                                                                  Раз уж пошел такой разговор на Rust тоже можно github.com/DanielKeep/cargo-script, а еще вроде как идет разработка github.com/PistonDevelopers/dyon.
                                                                    0

                                                                    В топике написано "можно ли..." — автор просто ответил на вопрос топика. А диспут разгорелся по вопросу "что лучше". Автор — молодец, плюсую. Больше интересных и спорных мыслей и постов!

                                                                      +1
                                                                      Я должен подготовить «интерпретатор» скрипта c++. Написать его можно на чем угодно, да хоть на bash (это в последний раз, хотя не точно). Вот что у меня получилось.

                                                                      Позволите непрошенное ревью?


                                                                      Заголовок спойлера
                                                                      #!/bin/bash
                                                                      # Для такого простого скрипта можно и не требовать Bash,
                                                                      # достаточно было бы /bin/sh.
                                                                      
                                                                      msg_file=/dev/null
                                                                      #msg_file=/dev/stdout
                                                                      
                                                                      tmp_path=$HOME"/.cache/c++/"
                                                                      # Тут бессмысленные кавычки. Чтобы от них была польза,
                                                                      # стоило взять в них всю правую часть присваивания целиком.
                                                                      
                                                                      mkdir -p $tmp_path
                                                                      # Нужно так: mkdir -p "$tmp_path"
                                                                      # Иначе пробелы в $HOME могут полностью изменить смысл
                                                                      # команды.
                                                                      
                                                                      tmp_file=$1".c++"
                                                                      exe_file=$1".bin"
                                                                      # Снова бессмысленные кавычки. Кроме того, неплохо было бы
                                                                      # проверить, что переменная вообще установлена, прежде чем
                                                                      # что-то компилировать.
                                                                      
                                                                      if test $1 -nt  $tmp_path$exe_file; then
                                                                          # Вы же вроде в шебанге потребовали Bash, так зачем
                                                                          # использовать test? И да, снова кавычки. Это в [[ строки
                                                                          # можно не квотировать.
                                                                      
                                                                          # Кроме того,
                                                                          # у вас часто повторяется выражение "$tmp_path$exe_file",
                                                                          # имеет смысл сделать для него переменную. А заодно добавить
                                                                          # в конкатенацию слеш, чтобы логика не зависела от того,
                                                                          # оканчивается ли $tmp_path на слеш или нет.
                                                                      
                                                                          echo "Need to recompile.." > $msg_file
                                                                          # Я бы просто убрал дебажные сообщения, чтобы не смущать
                                                                          # читателя. Иллюстрации идеи они не помогают.
                                                                      
                                                                          tail -n +2 $1 > $tmp_path$tmp_file
                                                                          # Нужны кавычки. Кроме того, если вырезать из исходника
                                                                          # первую строку, то диагностические сообщения компилятора
                                                                          # станут указывать не туда. Мой вариант:
                                                                          # echo -n "//" | cat -- - "$1" > "$tmp_path/$tmp_file"
                                                                      
                                                                          eval "g++ -o $tmp_path$exe_file $tmp_path$tmp_file > /dev/null 2>&1"
                                                                          # Я не совсем понял, для чего здесь eval?
                                                                          # Почему бы просто не вызвать компилятор без него?
                                                                      
                                                                          if [ $? -eq 0 ]
                                                                          then
                                                                          echo "Compiled ok" > $msg_file
                                                                          else
                                                                          echo "Compile error" > $msg_file
                                                                          exit 255
                                                                          fi
                                                                      fi
                                                                      
                                                                      eval "$tmp_path$exe_file $@1"
                                                                      # Что значит конструкция "$@1"?
                                                                      
                                                                      # Тут следует сделать как-то так:
                                                                      # shift ; exec "$tmp_path/$exe_file" "$@"
                                                                      # 
                                                                      # В этом случае запускаемая команда заменит собой запустивший её
                                                                      # процесс и не возникнет проблем с перенапрвлением ввода и вывода
                                                                      # внутрь и извне "скрипта".

                                                                      Only users with full accounts can post comments. Log in, please.