サムネイル
2022-03-12
2023-06-22

研究やら業務でシェル使ってる人なら、alias なり function なりでコマンドを自分好みにカスタマイズしている人が多いと思います。下は私がアカウントを持っているサーバー(5つくらいある)に共通で書いている .bashrc です(個別だと他にもいろいろ書いてる)。

# alias
alias ll='ls -alFX'
alias ..='cd ../'
alias ..2='cd ../../'
alias ..3='cd ../../../'
alias wi='which'
alias g='grep'
alias py='python'
alias sai='sudo apt install -y'
alias update='echo -e "\n\e[33m##### Update list of packages. #####\e[m\n" && sudo apt update && echo -e "\n\e[33m##### List of packages is updated. #####\n##### NEXT: Upgrade all packages #####\e[m\n" && sudo apt upgrade && echo -e "\n\e[33m##### All installed packages are upgraded. #####\n##### NEXT: Remove packages that are no longer needed #####\e[m\n" && sudo apt autoremove && echo -e "\n\e[33m##### Packages that are no longer needed for the update are removed. #####\n##### NEXT: Clean up cached files #####\e[m\n" && sudo apt clean && echo -e "\n\e[33m##### all cached deb files are deleted. #####\e[m\n"'
alias cp='cp -i'
alias mv='mv -i'
alias rm='rm -i'
alias e='exit'
alias unbz2='tar xvjf'
alias dig='dig any +noall +answer'

# function
bz2 () {
    tar cvjf $1.tar.bz2 $1
}

私はサーバーだけでなく、開発機自体も ubuntu を使っているので CUI には日ごろからお世話になっており、快適さを求めて常にカスタマイズを重ねています。

コマンドとしていろいろと自由度の高いことをするには結局シェルスクリプトファイル (.sh) を作ってそれを実行するのが一番だと思うが、せっかくなのでパスをしっかりと通してオプションもつけていろいろと自由にコマンドを自作するのを練習してみました。

環境と今回のお品書き

  • Ubuntu 20.04.4 LTS
  • GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)

今回はサンプルとして、「ゴミ箱に送る」操作をする trash コマンドを作成します。これでrm -rf をしてしまい取り返しのつかない事態になることからおさらば。

仕様として、

  • $ trash ファイル名 で、ファイルをゴミ箱フォルダに移動する
  • -h オプションでヘルプを表示
  • -l オプションでゴミ箱リストを表示
  • -c でゴミ箱を空にする
  • 30日以上経過したファイルは自動で削除(するように cron に登録する)
  • パスを通して普通のコマンドのように使えるようにする(大前提)

これらを一つのコマンドで実現できるようにします。

制作

準備

まず、自作コマンドを入れておくディレクトリを作成します。
それとゴミ箱ディレクトリを作成します。今回はコマンド用ディレクトリを .__command__、ゴミ箱を .__trash__ という名前で作ることとします。

$ mkdir ~/.__command__ ~/.__trash__

次に実行ファイルのパスを通します。
.bashrc を開いて、環境変数の $PATH に ~/.__command__ を追加します。

export PATH=~/anaconda3/bin:$PATH:~/.__command__

私は anaconda もいれているのでこのような記述ですが、関係ない人は export PATH=$PATH:~/.__command__ で大丈夫です。

bash における PATH は、実行するファイルを検索するディレクトリを : 区切りで定義します(左側ほど優先度高)。
ですので上の記述は、元の PATH により高い優先度で anaconda を通し、より低い優先度で __command__ を通しています。コマンドの衝突を避けるため、低優先度でパスを通します。

ファイル作成

といいつつ完成してからこの記事を書いているので、完成形のみ載せます。

$ vi ~/.__command__/trash

.__command__ の中にシェルスクリプトを作成します(.sh は不要)。

getopts を利用してオプションを受け取れるようにします。

#!/bin/bash
# help
function usage {
    cat <<EOM
Usage: $(basename "$0") [OPTION]... SOURCE...
  -h          Display help
  -c          Clear your trash can.
  -l          Display list of your trash can.
  -o          Delete files older than 30 days (Use for auto remove).
EOM
  exit 0
}

trashdir=~/.__trash__

# options
while getopts cloh optKey; do
    case $optKey in
        c)
            ls -AFmt $trashdir
            read -p "clean trash can? (y/n):" yesnot
            case $yesnot in
                [yY] | [yY]es | "YES" ) `rm -rf ${trashdir}/*` && echo 'trash can has been cleaned.' ;;
                *) echo 'cancelled.' ;;
            esac
            exit 0
        ;;
        o)
            find $trashdir -name "*" -mtime +30 | xargs rm -rf
            exit 0
        ;;
        l)
            ls -AFt1 $trashdir
            exit 0
        ;;
        h | *)
            usage
            exit 1
        ;;
  esac
done

if [ ! $1 = '' ]; then
    touch $1
    mv -i $1 $trashdir/
    cat << EOM
${1} has been moved to your trash can (${trashdir}/).
If you would like to check your trash can, do 'trash -l'.
EOM
else
    usage
    exit 1
fi

bash の function や shell スクリプトを実行する際の引数は $1, $2, … という変数で受け取ることができます。

今回は getopts に渡すオプションに変数を渡すものが無かったのですが、値を渡す必要がある場合は

while getopts c:loh optKey; do

というように : を追加すると、その直前のオプション(ここでは c )に引数が必要になります。

$ touch gomi
$ trash gomi
gomi has been moved to your trash can (~/__trah__/).
If you would like to check your trash can, do 'trash -l'.
$ trash -l
gomi
$ trash -c
gomi
clean trash can? (y/n):y
trash can has been cleaned.

こんな感じで無事にゴミ箱に送るコマンドができました。

ゴミ箱に送られてから30日で自動削除されるようにする

最後にゴミ箱に送ったファイルを、ゴミ箱を空にする(trash -c)を実行しなくても勝手に30日経ったら消えるようにします。

先ほど作ったスクリプトの中で -o オプションを作ってあります。これを実行すると、ゴミ箱の中で30日以上経過したものだけ削除できます。

都度手動で実行するのも手間なので、 cron に定期的にやってもらいましょう。

$ crontab -e

初回は多分エディタを聞かれるので、自分の使いたいエディタを選択してください。
cron の設定ファイルが開くので、一番最後に以下の行を追加します(ユーザ名は環境に合わせて)。

 0 0 * * * /home/{ユーザ名}/.__command__/trash -o

これで毎日0時0分に trash -o が自動で実行されて古いファイルが消えていきます。