初歩のシェルスクリプトで遊ぶ[シェルスクリプトの注意点はどこだろう(1)]

シェルスクリプトの勘所」っぽい内容ですが、私が今、気をつけてるポイントというだけです。私は素人なだけでなく単なる初心者で、解説記事を書く実力はありません。半年も経てば私も気が変わってる可能性は高いです。参考程度にしてください。
そこまで自信が無いなら書くなよ、って気が自分でもするんだけれども……曖昧な考えをまとめるのに、書くのってちょうどいいので。

  • Ubuntu20.04
  • dashとbash

 

パイプはブレース「{}」で括って繋ぐのが基本、ブレース無しは省略した結果

いわゆる「はじめてのシェルの使い方入門」だと、パイプはコマンドどうしを直接に繋げる書き方で紹介されます。

$ ls | wc

スクリプトを書くときは、端末エミュレータでコマンドを叩くときとは別です。
パイプはブレースで括るのが基本、ブレースが無いのは省略した結果だ、と意識していると、便利です。

#!/bin/sh
{
ls
} | {
wc
}

パイプはコマンド一つどうし、whileループやforループと直結することが多いです。
しかし直結せずにブレースでくくってから繋げると、簡単な作業が簡単にできることが増えます。

#!/bin/sh
# 1行目を最終行に移動する

echo 'ヘッダー行
111111
222222
333333
444444' | {
read Line
cat -
echo "${Line}"
}

・実行結果

111111
222222
333333
444444
ヘッダー行

「テキストの行単位処理といえばwhile read」ですが、これをブレース無しで初めて書くと、定番の失敗をするわけです。

#!/bin/sh
# 1行目を最終行に移動したいができない

lineNo='0'
firstLine='1行目を入れておくシェル変数'

echo 'ヘッダー行
111111
222222
333333
444444' |
while read Line
do
lineNo=$(( ${lineNo} + 1 ))

if test "${lineNo}" -eq 1 ; then
  firstLine="${Line}"
  continue
fi

echo "${Line}"
done

echo "${firstLine}"

・処理結果

111111
222222
333333
444444
1行目を入れておくシェル変数

こういうとき、結局はブレースで括って解決します。

#!/bin/sh
# 1行目を最終行に移動したいができなかった

lineNo='0'
firstLine='1行目を入れておくシェル変数'

echo 'ヘッダー行
111111
222222
333333
444444' | {
while read Line
do
lineNo=$(( ${lineNo} + 1 ))

if test "${lineNo}" -eq 1 ; then
  firstLine="${Line}"
  continue
fi

echo "${Line}"
done

echo "${firstLine}"
}

・処理結果

111111
222222
333333
444444
ヘッダー行

シェル変数「firstLine」の中身を「while read」の外に持ち出せるわけですが、やっぱりこれもブレースが必要です。
そして、ブレースで括るならば、単に1行目を最終行に移動したいだけの簡単な処理なら、最初のスクリプトでも十分です。

1行目だけでなく、2行目でもいけますね。

#!/bin/sh
# 2行目を最終行に移動する

echo 'ヘッダー行
111111
222222
333333
444444' | {
read Line
echo "${Line}"
read Line
cat -
echo "${Line}"
}

・実行結果

ヘッダー行
222222
333333
444444
111111

さらに例えば「1行目のみ削って2行目以降をwhile readで処理したい」ときは、

#!/bin/sh
# 1行目を削って残りは while read


echo 'ヘッダー行
111111
222222
333333
444444' | {
# 1行目のみ読み込むが、出力はしない。
read Line

# 2行目以降を読み込み、処理してから出力する。
while read Line
do
echo ____"${Line}"____
done
}

・処理結果

____111111____
____222222____
____333333____
____444444____

 

コマンドをふたつ組み合わせてパイプに繋ぐときも、ブレースで括れば難しいことなく、そのまま書けます。

#!/bin/sh
# 連番を増減させてパイプに繋ぐ

{
# 1 2 3
seq 1 3
# 4 3 2 1
seq 4 -1 1
} | {
cat -
}

・処理結果

1
2
3
4
3
2
1