【競プロ】どのディレクトリからでもすぐに競プロできるようなシェルスクリプトを書いた
いつでもどこでもすぐに競プロの問題解き始められるようなシェルスクリプトを書きました。イメージとしては、サイト名、コンテスト名、問題名を入力すると対応するディレクトリに移動して、テンプレファイルからC++ファイルを作成、問題のサンプルテストケースを取得してinファイルに書き込む、といった感じです。
コードはこちら
https://github.com/hpano/CompetitiveProgramming/blob/master/compp.sh
実際の動作はこんな感じ。全然関係ないディレクトリから、AtcoderのABC173のディレクトリに移り、A問題とB問題のサンプルテストケースを取得しています。
この問題のコンテストページはこちら
さてコードを見ていきましょう。まずは入力部分です。
ここでは、-dオプションの後に続けられたものをディレクトリ名として配列directorys、-fオプションの後に続けられたものを作成したいファイル名として配列filesに突っ込んでいます。
while test "$1" != ""; do case $1 in -*) if [[ "$1" =~ 'h' ]] || [[ "$1" =~ '-help' ]]; then hflag=true elif [[ "$1" =~ 'd' ]] || [[ "$1" =~ '-directory' ]]; then while [[ $2 != -* ]] && [[ $2 != "" ]]; do directorys+=($2) shift done elif [[ "$1" =~ 'f' ]] || [[ "$1" =~ '-file' ]]; then while [[ $2 != -* ]] && [[ $2 != "" ]]; do if [[ $2 =~ "." ]] && [[ $2 != *.cpp ]]; then echo "[compp] Invalid file $2 !" echo " You can input *.cpp or *" exit 1 fi files+=(${2%.cpp}) shift done else echo "[compp] Invalid option $1 !" usage exit 1 fi shift ;; *) echo "[compp] Invalid input $1 !" usage exit 1 ;; esac done directorys=(${directorys[@]//// })
続いて競プロ用のルートディレクトリのパスを調べます。どこからでもbashファイル実行できるようにこのディレクトリのパスを通してあるので、whichコマンドでパスを取得します。一応パスを通していなくても使えるよう、その場合はパスの入力を求めます。ここで"n"を入力すると、今いるディレクトリを競プロ用のルートディレクトリとみなします。
declare rootpath=$(which compp.sh) if [[ ${rootpath} == "" ]]; then read -p "[compp] Input competitive programing directory's root path or 'n' to give up cd: " rootpath fi if [[ ${rootpath} == "n" ]]; then rootpath=$(pwd) elif [[ ${rootpath: -3} == ".sh" ]]; then rootpath=${rootpath%\/*} fi
そしてそのディレクトリに移動し、目的のディレクトリまでさらに移動します。競プロ用のルートディレクトリから順に、directorysに入っているディレクトリを辿っていき(なければ作成するか選択でき)、たどり着いた場所にファイルを作成するといった感じです。
declare yn cd ${rootpath} for dir in ${directorys[@]}; do if [[ -d ${dir} ]]; then cd ${dir} else read -p "[compp] Directory '${dir}' not exists. make? [y/n]: " yn if [[ ${yn} == "y" ]]; then mkdir ${dir} && cd ${dir} fi fi done echo "[compp] Now at $(pwd)"
最後に前回の記事で作成したadd.shを使い、配列filesに入っているファイルを作成します。こちらもパスが通っていなければ、add.shのパスの入力を求めます。
declare addpath=$(which add.sh) if [[ ${addpath} == "" ]]; then read -p "[compp] Input add.sh path or 'n' to give up add file: " addpath fi if [[ ${addpath} == "n" ]]; then exit 1 elif [[ ${addpath: -3} != ".sh" ]]; then if [[ ${addpath: -1} != "/" ]]; then addpath+="/" fi addpath+="add.sh" fi ${addpath} ${files[@]}
このシェルスクリプトの中でcdをしてディレクトリの移動をしているのですが、シェルスクリプトは基本的には現在のシェルとは別のシェルで実行されるので、普通に実行しただけだと現在のシェルを移動させることはできません。実行する際に.コマンドかsourceコマンドを使用する必要があります。
こちらのサイトが参考になりました。
毎回.を打つのも忘れそうだしめんどくさいので、~/.bashrcに.コマンドありでこのシェルスクリプトを実行する関数を用意しました。
# competitive programing by hpano compp(){ . compp.sh $@ }
これで実行する際にはcompp -d [ディレクトリ] -f [ファイル]
と入力することで、どこからでも実行できるようになりました。
また、ここまでで色々パスを通したり、.bashrcに書き込んだり、シェルスクリプトのパーミッションを変更したりと色々設定があって忘れそうなので、それら設定を一括で行えるsetting.shを作成しました。
https://github.com/hpano/CompetitiveProgramming/blob/master/setting.sh
#/bin/bash function write2bash_profile() { local bashpro=$(cat ~/.bash_profile) if [[ !(${bashpro} =~ "# competitive programing by hpano") ]]; then local yn read -p "[setting] Write PATHs to ~/.bash_profile now? [y/n]: " yn while [[ ${yn} != "y" ]] && [[ ${yn} != "n" ]]; do read -p "Answer only y or n [y/n]: " yn done if [[ ${yn} == "y" ]]; then echo "# competitive programing by hpano" >> ~/.bash_profile echo "export PATH=\$PATH:${dirpath}" >> ~/.bash_profile source ~/.bash_profile echo "[setting] Wrote PATHs to ~/.bash_profile" fi fi } function write2bashrc() { local bashrc=$(cat ~/.bashrc) if [[ !(${bashrc} =~ "# competitive programing by hpano") ]]; then local yn read -p "[setting] Write functions to ~/.bashrc now? [y/n]: " yn while [[ ${yn} != "y" ]] && [[ ${yn} != "n" ]]; do read -p "Answer only y or n [y/n]: " yn done if [[ ${yn} == "y" ]]; then echo "# competitive programing by hpano" >> ~/.bashrc echo "compp(){" >> ~/.bashrc echo " . compp.sh $@" >> ~/.bashrc echo "}" >> ~/.bashrc source ~/.bashrc echo "[setting] Wrote functions to ~/.bashrc" fi fi } declare dirpath=$(dirname $0) write2bash_profile write2bashrc chmod +x ${dirpath}/setting.sh chmod +x ${dirpath}/add.sh chmod +x ${dirpath}/compile.sh chmod +x ${dirpath}/compp.sh chmod +x ${dirpath}/remove.sh chmod +x ${dirpath}/run.sh echo "[setting] Finish setting"
これでますます競プロが捗るはずです。頑張って精進します。