Недавно пришлось мне опять/снова погрузиться в чудесный мир программирования 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 идея та же, реализация другая. Потом оказалось, что есть и другие реализации.
В общем, испытал небольшое разочарование в собственной неисключительности. Однако, поискал по Хабру — похожего не нашел. Может кому-то покажется хотя бы любопытным?
CrazyAlex25
CERN использует cling (до этого был cint ). Для Си есть tcc с параметром -run