開発

Bashシェルスクリプト開発Tips

要件として外部からPython等のプログラミング言語の導入やライブラリのインストールを制限されているもしくは禁止といった環境でプログラム的処理をするにはシェルスクリプトが選択肢となってきます。

シェルスクリプトは近代的ツールでも前処理として使ったり、ちょっとした用途で使うにはまだまだ需要があります。ここではそういった小規模な使い方ではなく中大規模な比較的ガッツリとプログラム開発としてシェルスクリプトを使う場合を想定します。

ですが、シェルスクリプトはバグが混入しやすいものです。プログラム開発には向いていません。少しでもバグを減らすには過去のノウハウの利用とツールを駆使すべきです。

シェルスクリプトは基本的にはコマンドのリストです。と、割り切っておくとイラつくことは多少なりとも軽減できます。

以下、工事中

コーティング規約

シェルスクリプトの問題の一つは可読性の低いコードになりがちな点です。意識してコメントを入れたりテクニカルなワンライナーを多用しないようにした方がよいと思います。

可読性、保守性を保つためにコーディング規約を定めてソレに沿ったプログラミングがよいです。コーディング規約がない場合は、比較的有名なGoogleのコーディング規約Shell Style Guideが使えると思います。少ない労力で統一するにはコード整形ツールを使うと良いでしょう。

styleguide

Style guides for Google-originated open-source projects

テクニカルライティング

開発はコーディングだけでなく関連ドキュメントの作成も必要になってきます。簡潔でわかりやすく数年経って見返してみても理解ができるものが理想です。開発面で言うとソースコードのコメント等は特に重要になります。

遠回しな書き方、抽象的な文言、やたら長い説明、解釈が複数パターンあり得る書き方などただ書けばいいというものではないのです。

システムが長年メンテナンスされてない、担当者が退職しシステムの動作内容がわからない等ということは往々にしてあり得ることです。マニュアルやドキュメント、ソースコードのコメントがしっかりしていれば、そんな不幸なシステムの担当になってしまった場合もなんとかなる場合があります(システムがそんな状況であればドキュメント類の状況もお察し、という感じではありますが)

そのような状況を生む一因として、コーディングの学習リソースは多数あるので学んだ事はあるがドキュメントの書き方というものはあまり学習リソースが無いので今まで学んでこなかった、というのが現状かと思います。

社内でドキュメントスタイルガイドや用語集、テンプレートが整備されていればある程度品質の高いものが作れますが、無い場合はそれらの整備が必要でしょう。

シェルスクリプト開発だけでなくあらゆるシステム開発(もしかして日常の事務作業にも)に活かせるのでテクニカルライティングのスキルを習得は応用範囲が広いです。保守メンテナンスではむしろこれらが重要だったりしますので是非取得して実践に活かしましょう。

Technical Writing  |  Google for Developers

Technical Writing Courses for Engineers

Google社のテクニカルライティングの基礎教育資料がとても良かったので紹介したい – Qiita

はじめに エンジニアにとって、仕様書などの技術的な文章を書くこと(テクニカルライティングとも言います)は避けて通れません。ただ20年来多くのエンジニアの方々と同僚として接してきて思うことは、エンジニアの方の中には「文章を書く」ということに苦手意識がある方が一定数いるという…

テクニカルライティングの基本 2023年版

Strict Mode

正式なものではないですが、Strict Mode設定として出回っている設定として

set -euo pipefailCode language: JavaScript (javascript)

があります。

意図しないエラーを減らすために有効そうですが、エラーを想定したコードもありえるので場合によっては使わなかったり、オプション内容を変更して使うのもアリだと思います。

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}"
Code language: PHP (php)

周辺ツール関連

静的解析ツール

shellcheckはコードを解析して誤動作を起こしやすそうな書き方を指摘したりよりベターな書き方を指摘してくれます。中規模以上のスクリプトを書くときは必須と言えるツールではないでしょうか

ShellCheck – shell script analysis tool

ShellCheck finds bugs in your shell scripts

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 – mvdan/sh

Visual Studio Code

近年のエディターはプラグインでSSHができたりエディター自身の動作を変えたりと様々な機能拡張が可能でリッチになっています。その分、多少動作は重くなりますがそのコスト以上の恩恵を得られると思います。VScodeは最近の定番ではないでしょうか。

ここで紹介している幾つかのツールもプラグインで連携できるのでワンプレイスでリアルタイムに動作してくれるのはありがたいです。

Visual Studio Code – The open source AI code editor

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://tio.run/#bash

https://www.mycompiler.io/new/bash

https://www.jdoodle.com/test-bash-shell-script-online/

https://www.onlinegdb.com/

https://onecompiler.com/bash

https://paiza.io/ja/projects/new?language=bash

https://wandbox.org/

コードジェネレーター

スクラッチからコードを書くより今後はこのようなツールの利用が主流になるのかもしれません。

著作権や品質が気になるので現時点では参考程度の利用でしょうか。

今後はオープンソースのライセンスのような考え方やテストも含めたコード生成を行う等になるかもしれません。時間によって解決されるのでしょう。

CodePal

CodePal is an AI coding companion with tools to generate, fix, refactor and explain code in 60+ languages.

$((算術式))

Bash $((算術式)) のすべて – A 基本編 – Qiita

Bash の算術式の基本について詳細に解説します! ※この記事は AdC 2016 Shell Script 4日目 Bash $((算術式)) のすべて – Qiita の衛星記事です (が、実のところこちらの記事のほうが実用性が高いような気がします…)。 関連記事一覧:…

よく使いそうなコマンド

grep

grepで特定の文字(文字列)をm~n個含む行を抽出する方法 – Qiita

はじめに 今回はLinuxのgrepコマンドを使って**「特定の文字(文字列)を任意の個数含む行」**を抽出する方法をご紹介します。(というか思いついたので書く) (↓↓※すべてコマンドの前にcat 検索したいファイル |をつけます) ・特定の1文字(A)を、m~n個含む…

# 検索対象データ
DATA="
ABC
ABCABC
ABCABCABC
BCA
BCABCA
BCABCABCA
CAB
CABCAB
CABCABCAB"

# 文字Aが2から3回含まれる文字列を抽出
echo "${DATA}" | egrep "^([^A]*A){2,3}[^A]*$"
Code language: PHP (php)

awk

XMLのようなマークアップ言語やJSONのような構造化データのレコードを一つずつファイルに書き出すスクリプト

XMLやJSONなどはデファクトスタンダードなものは専用コマンドやライブラリが充実していると思われるのでそれらを使用すれば良いかもしれません。

ただし世の中には中途半端に構造化されたデータがあるのでそれらに対処したい時があります。

手元に適切なサンプルデータが無いのでJSONでやってみます。この例では2-30行が1レコードで合計3レコードあります。

2行がレコードの開始行、30行が終了行になっているのでこれにマッチした場合、ファイル書き込み開始処理と終了処理をする。それ以外は通常の書き込み。BEGINセクションで初期化とファイル名の定義を行っている。

[
  {
    "_id": "66b907eb97827f07a301ac50",
    "isActive": false,
    "name": "Glenna Lowery",
    "email": "glennalowery@orbin.com",
    "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": "coledale@orbin.com",
    "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": "doloresvelez@orbin.com",
    "tags": [
      "non",
      "reprehenderit",
      "pariatur",
      "amet",
      "eu",
      "nulla",
      "eiusmod"
    ],
    "friends": [
      {
        "id": 0,
        "name": "Rosella Pittman"
      },
      {
        "id": 1,
        "name": "Lora Norris"
      },
      {
        "id": 2,
        "name": "Waters Gaines"
      }
    ]
  }
]Code language: JSON / JSON with Comments (json)
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 で実行を想定Code language: PHP (php)

sed

sedでこういう時はどう書く? – Qiita

シェルでデータ加工するときSEDをよく使いますが、その利用例と覚え書きです、参考になれば sedコマンドはLinux/Unix/BSD/OSXに標準で入っているので、Macの人なら覚えておくと捗るかも(Linuxとは少し違うのでそこは調べてね?) 当方の利用環境がRedha…

管理人

Recent Posts

情報セキュリティマネジメント試験取得への道

スキルアップを図るべく情報セキ…

2か月 ago

ファイナンシャルプランナー3級試験取得への道

スキルアップを図るべくファイナ…

2か月 ago

[rust] New Type Patternを使ってみる

DDDの考えを取り入れることで…

5か月 ago

RustでDDDの要素を取り入れてみる

前回SOLID原則というものを…

5か月 ago

期間限定!書籍無料キャンペーン2025

「mdBookではじめるKin…

5か月 ago