Slack通知のシェルスクリプト
WindowsとLinuxの両方で動くSlack通知用シェルスクリプトを書いてみました。
Table of Contents
はじめに
動作環境
以下の環境で動作することを確認済みです。
環境 | バージョン |
---|---|
git bash(Windows 10 Home 10.0.18362) | GNU bash, version 4.4.23(1)-release (x86_64-pc-msys) |
bash (Ubuntu 18.04.2 LTS) | GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu) |
前提
Incoming Webhooksのレガシーカスタムインテグレーション を使っています。
冒頭に記載のあるとおり、この方法は非推奨です。
しかし、通知先のchannelをパラメータで指定したかったから敢えてこれを使用しています。
実行
export SLACK_WEBHOOK_URL=https://hooks.slack.com/services/..............
./slack.sh "#your_channel" "スマイル一番"
こんな感じに通知されます。
実装
ソースコード
以下のようなslack.sh
を作成します。
#!/bin/bash
set -eu
post_slack() {
# ex: "#times_hoge"
channel=$1
# ex: "hoge"
user=$2
# ex: "smile"
emoji=$3
# ex: "ほげほげ"
message=${4//'"'/'\"'}
# list: good / danger
color=$5
file=$(mktemp)
trap 'rm ${file}' EXIT
cat << EOJ > "$file"
{
"link_names": 1,
"channel": "${channel}",
"username": "${user}",
"icon_emoji": ":${emoji}:",
"attachments": [
{
"color": "${color}",
"text": "${message}"
}
]
}
EOJ
curl -s -S -X POST -d @"$file" "${SLACK_WEBHOOK_URL}"
}
post_slack "$1" smile_bot smile "$2" good
ポイント
実装にあたり、いくつかポイントがあります。
日本語のメッセージを送信できるようにする
Windowsの場合のみ日本語メッセージが送れない..という問題がありました。
以下はそのときのcurl
コマンドです。
curl -s -S -X POST --data-urlencode 'payload={"link_names": 1, "channel": "'"${channel}"'", "username": "'"${user}"'", "icon_emoji": "'":${emoji}:"'", "attachments": [{"color": "'"${color}"'", "text": "'"${message}"'"}]}' ${SLACK_WEBHOOK_URL}
curl -X POST --data-urlencode
でマルチバイト文字をPOSTできます。
しかし、Windowsの場合はエンコーディングがCP932
に強制されてしまいます。
SlackのAPIはUTF-8
を要求するため、POSTしたJSONが正しくparseされずエラーになります。
解決策として、JSONをUTF-8エンコードした一時ファイルを作成し、curl --data-binary @{file}
でファイルを指定するようにしました。
file=$(mktemp)
echo 'payload={"link_names": 1, "channel": "'"${channel}"'", "username": "'"${user}"'", "icon_emoji": "'":${emoji}:"'", "attachments": [{"color": "'"${color}"'", "text": "'"${message}"'"}]}' > "$file"
curl -s -S -X POST --data-binary @"$file" ${SLACK_WEBHOOK_URL}
JSONを読みやすくする
1行で書かれたJSONは読みにくいです。
curl --data-binary
の代わりにcurl -d
を使うと改行の含むJSONをPOSTできます。
また、ヒアドキュメントを使うことで"'"
といった複雑なコーテーションを排除しました。
file=$(mktemp)
cat << EOJ > "$file"
{
"link_names": 1,
"channel": "${channel}",
"username": "${user}",
"icon_emoji": ":${emoji}:",
"attachments": [
{
"color": "${color}",
"text": "${message}"
}
]
}
EOJ
curl -s -S -X POST -d @"$file" ${SLACK_WEBHOOK_URL}
一時ファイルが残らないようにする
rm -rf ${file}
を最後に実行すれば問題ないでしょうか?
途中でエラーが発生したり、強制終了されたら一時ファイルがゴミとして残ってしまいますね😅
mktemp
で作られるファイルパスはテンポラリー領域を指します。
放っておいても定期的に削除されるかもしれませんが、すぐ削除した方が安心です。
trap
コマンドでEXIT
シグナルを受け取ったとき、ファイルを削除するようにしました。
file=$(mktemp)
trap 'rm ${file}' EXIT
cat << EOJ > "$file"
{
"link_names": 1,
"channel": "${channel}",
"username": "${user}",
"icon_emoji": ":${emoji}:",
"attachments": [
{
"color": "${color}",
"text": "${message}"
}
]
}
EOJ
curl -s -S -X POST -d @"$file" ${SLACK_WEBHOOK_URL}
set -x slack.sh
でデバッグ出力すると、必ず最後にrm ${file}
が実行されることを確認できます。
ダブルクォーテーションの考慮
message
にダブルクォーテーションを含むと、ivalid payloadエラーになります。
そのため変数代入時に"
を\"
に置換して代入する必要があります。
# ex: "ほげほげ"
message=${4//'"'/'\"'}
総括
Windows(git bash)とLinux(bash)の両方で動くSlack通知用シェルスクリプトを紹介しました。
文字コードや使えるコマンドの制限など、Linuxだけのときに比べて気をつける必要があります。
しばらくの間は安心してSlack通知ができそうです😄