最近Pythonを覚えた。
Linuxなら大抵最初から入っているので、シェルスクリプト代わりにちょい遣いできるようになりたい。
でも、やってみるとPythonめどい。
なんといっても仮想環境あってこそ、モジュールばかすか入れてこそなので、「ファイル1枚でそのまま動く」Bashスクリプトのお手軽さがまったくない。
Python動かすためにまず環境準備する必要があるとか、「最初から入っているからかんたん♪」とか秒で消滅。
めっちゃヘビーウェイトやん。
なら、シェルスクリプトと合体させて、1ファイルの中で環境も作っちゃえばいいんじゃね?
と思ってやってみた。
ここでは シェルスクリプト→Pythonの順で実装していますが、これを逆順にした転置バージョンも作ってみました。お好みでどうぞ。
#!/bin/sh
X=r''''
#
# Shell Script from here
#
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SCRIPT_PATH="$SCRIPT_DIR/$(basename "$0")"
VENV_PATH="$SCRIPT_DIR/.$(basename "$0").venv"
# Python仮想環境を作成・実行
if [ -f "$VENV_PATH/bin/activate" ]; then
VENV_STATUS=exist
else
python3 -m venv "$VENV_PATH"
VENV_STATUS=new
fi
. "$VENV_PATH/bin/activate"
# 仮想環境を新規に作成した場合はpipを最新化
if [ $VENV_STATUS = new ]; then
pip install -q --upgrade pip
fi
# 必要なパッケージをインストール
sed -n 's/^# REQUIREMENTS.TXT:\(.*\)/\1/p' "$SCRIPT_PATH" >"$VENV_PATH/requirements.txt"
pip install -qr "$VENV_PATH/requirements.txt"
# Pythonスクリプトを実行
python3 "$SCRIPT_PATH" "$@"
exit $?
: "$X" <<'##END_OF_PYTHON##' ' '''
#
# Python Script from here
#
print("Hello Python!")
##END_OF_PYTHON##
# ----------------------------------------------------------------------------
# requirements.txt from here
# REQUIREMENTS.TXT:Jinja2==3.1.6
# REQUIREMENTS.TXT:MarkupSafe==3.0.3
あとは # Python Script from here 以下にゴリゴリ書く。
解説すると、X=r''''はシェルスクリプト的には変数定義。rと空文字列2つをつなげた r という値をシェル変数Xに代入してる。
Python的にも変数定義。X=r'''...''' で複数行(シェルスクリプト部分全体)を生文字列として変数Xに代入してる。つまり、シェルスクリプト部分はPython的にはXに代入されるだけの文字列で、構文的には意味がない。
シェルスクリプト部分は、exit $? まで続く。ここで実行終了するので、それ以降は何が書いてあっても関知しない。
けど PyCharm 上でエラーが出てうざいので、 : コマンドの引数としてヒアドキュメントを渡すようにして、そのヒアドキュメントにPython部分を閉じ込める。
ついでに最初に定義したXを使っていないと警告が出るのでここで使ってあげる。
: の最後の引数が ' ''' となっているが、これは一つの空白文字と空文字列をつなげたもので、Python コメントの終端 ''' を捻り出すために置いている。
''' でPython的に文字列が終わったあとはPythonの領域。
最後に requirements.txt もgrepで抜き出せる形でコメントとして置いておく。
こんな感じ。
残念なのは、PyCharmで書いてると X=r の前に import が追加されちゃったり、うっかり全フォーマットすると X=r'''' が X = r'''' に整形されて、実行すると
/usr/lib/xorg/Xorg.wrap: Only console users are allowed to run the X server
なんてエラーが出たりするところ。
X = r だとシェルスクリプト的にシェル変数定義じゃなくコマンド X の実行になってしまう。残念。
あと、シェル部分で exit($?) の後ろで : コマンドを使っている部分で「到達しないコード」警告が出るのは消せなかった。残念。
いじょ。
なにぶん当方Pythonニワカなもので、同じことを実現できるもっといい「フツーのやり方」があればご教示願いたい。
2025/11/15 内容を更新しました。
-
#!/usr/bin/shがMacでエラーになったので#!/bin/shに変更 -
pipが古いんだが!?とMacで文句垂れられたのでpip install --upgrade pipを追加 - shファイルとして見た時に PyCharm 上で $X が未使用との警告がでたので使用した
- sh部分の exit $? の後のエラーが気になったのでヒアドキュメントにした
- 上記に伴う説明内容の変更
- 転置バージョンの紹介を追記
- シェル部分は極力短くしたいのにだんだん長くなる。。。prz