要件として外部からPython等のプログラミング言語の導入やライブラリのインストールを制限されているもしくは禁止といった環境でプログラム的処理をするにはシェルスクリプトが選択肢となってきます。
シェルスクリプトは近代的ツールでも前処理として使ったり、ちょっとした用途で使うにはまだまだ需要があります。ここではそういった小規模な使い方ではなく中大規模な比較的ガッツリとプログラム開発としてシェルスクリプトを使う場合を想定します。
ですが、シェルスクリプトはバグが混入しやすいものです。プログラム開発には向いていません。少しでもバグを減らすには過去のノウハウの利用とツールを駆使すべきです。
シェルスクリプトは基本的にはコマンドのリストです。と、割り切っておくとイラつくことは多少なりとも軽減できます。
以下、工事中
コーティング規約
シェルスクリプトの問題の一つは可読性の低いコードになりがちな点です。意識してコメントを入れたりテクニカルなワンライナーを多用しないようにした方がよいと思います。
可読性、保守性を保つためにコーディング規約を定めてソレに沿ったプログラミングがよいです。コーディング規約がない場合は、比較的有名なGoogleのコーディング規約Shell Style Guideが使えると思います。少ない労力で統一するにはコード整形ツールを使うと良いでしょう。
テクニカルライティング
開発はコーディングだけでなく関連ドキュメントの作成も必要になってきます。簡潔でわかりやすく数年経って見返してみても理解ができるものが理想です。開発面で言うとソースコードのコメント等は特に重要になります。
遠回しな書き方、抽象的な文言、やたら長い説明、解釈が複数パターンあり得る書き方などただ書けばいいというものではないのです。
システムが長年メンテナンスされてない、担当者が退職しシステムの動作内容がわからない等ということは往々にしてあり得ることです。マニュアルやドキュメント、ソースコードのコメントがしっかりしていれば、そんな不幸なシステムの担当になってしまった場合もなんとかなる場合があります(システムがそんな状況であればドキュメント類の状況もお察し、という感じではありますが)
そのような状況を生む一因として、コーディングの学習リソースは多数あるので学んだ事はあるがドキュメントの書き方というものはあまり学習リソースが無いので今まで学んでこなかった、というのが現状かと思います。
社内でドキュメントスタイルガイドや用語集、テンプレートが整備されていればある程度品質の高いものが作れますが、無い場合はそれらの整備が必要でしょう。
シェルスクリプト開発だけでなくあらゆるシステム開発(もしかして日常の事務作業にも)に活かせるのでテクニカルライティングのスキルを習得は応用範囲が広いです。保守メンテナンスではむしろこれらが重要だったりしますので是非取得して実践に活かしましょう。
Technical Writing | Google for Developers
Technical Writing Courses for Engineers
Google社のテクニカルライティングの基礎教育資料がとても良かったので紹介したい – Qiita
はじめにエンジニアにとって、仕様書などの技術的な文章を書くこと(テクニカルライティングとも言います)は避けて通れません。ただ20年来多くのエンジニアの方々と同僚として接してきて思うことは、エンジニ…
テクニカルライティングの基本 2023年版
Strict Mode
正式なものではないですが、Strict Mode設定として出回っている設定として
set -euo pipefail
があります。
意図しないエラーを減らすために有効そうですが、エラーを想定したコードもありえるので場合によっては使わなかったり、オプション内容を変更して使うのもアリだと思います。
Unofficial bash strict mode
Unofficial bash strict mode. GitHub Gist: instantly share code, notes, and snippets.
型
基本的にはシェルスクリプトに型は無い、と思っておいたほうが良いです。基本的に文字列です。
変数に対してlocal, declare, typeset等がありますが型(というか属性)の違う値を入れてもそのまま動いてしまう場合があるので注意が必要です。高級言語と同じような期待をしてはいけません。readonlyは比較的期待通りに動くので積極的に使っていきたいです。
使ったことはないですが、静的型付けを行いシェルスクリプトに変換する言語(トランスパイル)Cotowaliがあります。一般的な言語に近く理解しやすい文法らしいのでこういったものは有用かもしれません。しかし、学習コストがどのくらいかかるのかわかりません。
GitHub – cotowali/cotowali: A statically typed scripting language that transpile into POSIX sh
A statically typed scripting language that transpile into POSIX sh – cotowali/cotowali
整数
ErrorになりそうなケースもErrorにならないので注意が必要です。特にダブルクォーテーションを使うケースの場合は事前にバリデーションやノーマライズが必要かもしれません。
bash --version
set -x
declare -i var # 整数
var=10
echo "var=10: ${var}"
var=10.5 # 小数点あり Errorになる
echo "var=10.5: ${var}"
var=010 # 8進数
echo "var=010: ${var}"
var=0x10 # 16進数
echo "var=0x10: ${var}"
var=abc # 文字列 Errorにならない
echo "var=abc: ${var}"
var=@\\\%\&\! # 記号 Errorになる (計算式として認識?)
echo "var=@\\\%\&\!: ${var}"
var=+10 # 式
echo "var=10: ${var}"
var=-10 # 式
echo "var=10: ${var}"
var=15-10 # 式
echo "var=15-10: ${var}"
var=true # true (文字列として認識?)
echo "var=true: ${var}"
var=false # false (文字列として認識?)
echo "var=false: ${var}"
# ダブルクォーテーションを使った場合
echo "ダブルクォーテーションを使った場合"
var="" # 値なし
echo ${var}
echo "var=\"\": ${var}"
var="10"
echo "var=\"10\": ${var}"
var=" 10" # 左側にスペースあり
echo "var=\" 10\": ${var}"
var="10 " # 右側にスペースあり
echo "var=\"10 \": ${var}"
var=" 10 " # 両側にスペースあり
echo "var=\" 10 \": ${var}"
var="+ 10" # 数式とスペース
echo "var=\"+ 10\": ${var}"
var=" - 10 " # 数式とスペース
echo "var=\" - 10 \": ${var}"
var="2* 10" # 数式とスペース
echo "var=\"2* 10\": ${var}"
var="022* 10" # 8進数 数式にスペース
echo "var=\"022* 10\": ${var}"
var=" 0x10 * -10 " # 16進数 数式にスペース
echo "var= 0x10 * -10: ${var}"
var="foo=456" # 代入式
echo "var=\"foo=456\": ${var}"
echo "foo=: ${foo}"
var="foo = $foo$foo" # 代入式
echo "var=\"foo = \$foo\$foo\": ${var}" # エスケープしても認識されてしまう
echo "foo=: ${foo}"
var="foo=true" # 代入式
echo "var=\"foo=true\": ${var}"
echo "foo=: ${foo}"
var="foo=false" # 代入式
echo "var=\"foo=false\": ${var}"
echo "foo=: ${foo}"
readonly foo;
echo "var=\"foo=789\": ${var}" # readonly変数へ代入 Errorなし
echo "foo=: ${foo}"
周辺ツール関連
静的解析ツール
shellcheckはコードを解析して誤動作を起こしやすそうな書き方を指摘したりよりベターな書き方を指摘してくれます。中規模以上のスクリプトを書くときは必須と言えるツールではないでしょうか
GitHub – koalaman/shellcheck: ShellCheck, a static analysis tool for shell scripts
ShellCheck, a static analysis tool for shell scripts – koalaman/shellcheck
テストフレームワーク
GitHub – kward/shunit2: shUnit2 is a xUnit based unit test framework for Bourne based shell scripts.
shUnit2 is a xUnit based unit test framework for Bourne based shell scripts. – kward/shunit2
GitHub – bats-core/bats-core: Bash Automated Testing System
Bash Automated Testing System. Contribute to bats-core/bats-core development by creating an account on GitHub.
GitHub – shellspec/shellspec: A full-featured BDD unit testing framework for bash, ksh, zsh, dash and all POSIX shells
A full-featured BDD unit testing framework for bash, ksh, zsh, dash and all POSIX shells – shellspec/shellspec
ShellSpec – シェルスクリプト用のフル機能のBDDユニットテストフレームワーク – Qiita
ShellSpec はシェルスクリプト用に開発した BDD ユニットテストフレームワークです。初期版公開以降、多くの機能を追加しておりフル機能と言えるまでに成長したのですが公式サイトはほとんど更新し…
整形ツール
EditorConfigは各種エディターのプラグインとして提供されており、タブ幅やインデントをスペースにするかどうか等設定をもたせることができます。複数エディターを使っている場合、共通した設定で使えるので便利です。
EditorConfig
EditorConfig is a file format and collection of text editor plugins for maintaining consistent coding styles between different editors and IDEs.
shfmtがデファクトスタンダードらしいです。.editorconfigを参照してくれるようなのでいいですね。
別途バイナリをこちらからインストールすれば使えます。
GitHub – mvdan/sh: A shell parser, formatter, and interpreter with bash support; includes shfmt
A shell parser, formatter, and interpreter with bash support; includes shfmt – GitHub – mvdan/sh: A shell parser, formatter, and interpreter with bash support; includes shfmt
Visual Studio Code
近年のエディターはプラグインでSSHができたりエディター自身の動作を変えたりと様々な機能拡張が可能でリッチになっています。その分、多少動作は重くなりますがそのコスト以上の恩恵を得られると思います。VScodeは最近の定番ではないでしょうか。
ここで紹介している幾つかのツールもプラグインで連携できるのでワンプレイスでリアルタイムに動作してくれるのはありがたいです。
Visual Studio Code – Code Editing. Redefined
Bash Beautify - Visual Studio Marketplace
Extension for Visual Studio Code - Format / Beautify bash and shell scripts
EditorConfig for VS Code - Visual Studio Marketplace
Extension for Visual Studio Code - EditorConfig Support for Visual Studio Code
Bash Debug - Visual Studio Marketplace
Extension for Visual Studio Code - A debugger extension for bash scripts (using bashdb).
ShellCheck - Visual Studio Marketplace
Extension for Visual Studio Code - Integrates ShellCheck into VS Code, a linter for Shell scripts.
shell-format - Visual Studio Marketplace
Extension for Visual Studio Code - A formatter for shell scripts, Dockerfile, gitignore, dotenv, /etc/hosts, jvmoptions, and other file types
Playground
動作を手軽に確認できる環境として利用できます。
https://secure.sakura.ad.jp/cloud-shell/cpanel/
https://www.tutorialspoint.com/execute_bash_online.php
https://www.mycompiler.io/new/bash
https://www.jdoodle.com/test-bash-shell-script-online/
https://paiza.io/ja/projects/new?language=bash
コードジェネレーター
スクラッチからコードを書くより今後はこのようなツールの利用が主流になるのかもしれません。
著作権や品質が気になるので現時点では参考程度の利用でしょうか。
今後はオープンソースのライセンスのような考え方やテストも含めたコード生成を行う等になるかもしれません。時間によって解決されるのでしょう。
Code Generator
$((算術式))
Bash $((算術式)) のすべて – A 基本編 – Qiita
Bash の算術式の基本について詳細に解説します!※この記事は AdC 2016 Shell Script 4日目 Bash $((算術式)) のすべて – Qiita の衛星記事です (が、実の…
よく使いそうなコマンド
grep
grepで特定の文字(文字列)をm~n個含む行を抽出する方法 – Qiita
はじめに今回はLinuxのgrepコマンドを使って**「特定の文字(文字列)を任意の個数含む行」**を抽出する方法をご紹介します。(というか思いついたので書く)(↓↓※すべてコマンドの前にcat…
# 検索対象データ
DATA="
ABC
ABCABC
ABCABCABC
BCA
BCABCA
BCABCABCA
CAB
CABCAB
CABCABCAB"
# 文字Aが2から3回含まれる文字列を抽出
echo "${DATA}" | egrep "^([^A]*A){2,3}[^A]*$"
awk
XMLのようなマークアップ言語やJSONのような構造化データのレコードを一つずつファイルに書き出すスクリプト
XMLやJSONなどはデファクトスタンダードなものは専用コマンドやライブラリが充実していると思われるのでそれらを使用すれば良いかもしれません。
ただし世の中には中途半端に構造化されたデータがあるのでそれらに対処したい時があります。
手元に適切なサンプルデータが無いのでJSONでやってみます。この例では2-30行が1レコードで合計3レコードあります。
2行がレコードの開始行、30行が終了行になっているのでこれにマッチした場合、ファイル書き込み開始処理と終了処理をする。それ以外は通常の書き込み。BEGINセクションで初期化とファイル名の定義を行っている。
[
{
"_id": "66b907eb97827f07a301ac50",
"isActive": false,
"name": "Glenna Lowery",
"email": "[email protected]",
"tags": [
"exercitation",
"sit",
"magna",
"ullamco",
"dolor",
"quis",
"commodo"
],
"friends": [
{
"id": 0,
"name": "Mitchell English"
},
{
"id": 1,
"name": "Hattie Campbell"
},
{
"id": 2,
"name": "Boyle Pate"
}
]
},
{
"_id": "66b907eb05301fe51debfcda",
"isActive": true,
"name": "Cole Dale",
"email": "[email protected]",
"tags": [
"aliqua",
"ad",
"magna",
"consequat",
"aliquip",
"voluptate",
"voluptate"
],
"friends": [
{
"id": 0,
"name": "Lakisha Nixon"
},
{
"id": 1,
"name": "Kline Valentine"
},
{
"id": 2,
"name": "Juliette Nieves"
}
]
},
{
"_id": "66b907eb1a88abcb2f14dee4",
"isActive": false,
"name": "Dolores Velez",
"email": "[email protected]",
"tags": [
"non",
"reprehenderit",
"pariatur",
"amet",
"eu",
"nulla",
"eiusmod"
],
"friends": [
{
"id": 0,
"name": "Rosella Pittman"
},
{
"id": 1,
"name": "Lora Norris"
},
{
"id": 2,
"name": "Waters Gaines"
}
]
}
]
BEGIN {
prefix="JSON";
num=0;
record_begin="^[[:blank:]]{2}{$";
record_end="^[[:blank:]]{2}},?$";
}
# 不要文字列の場合は処理をスキップ
/(^\[$|^\]$)/ { next;}
# データ開始行の検知
$0 ~ record_begin {
filename = prefix sprintf("%06d",num) ".txt";
print > filename;
}
# データ開始終了行以外の処理
! ( $0 ~ record_begin || $0 ~ record_end ) { print >> filename;}
# データ終了行の検知
$0 ~ record_end { print >> filename;num++;}
# cat json.txt | awk -d -f test.awk で実行を想定
sed
sedでこういう時はどう書く? – Qiita
シェルでデータ加工するときSEDをよく使いますが、その利用例と覚え書きです、参考になればsedコマンドはLinux/Unix/BSD/OSXに標準で入っているので、Macの人なら覚えておくと捗るか…