---
title: シェルスクリプト浅めの深堀り
tags:  #lifull #シェルスクリプト #bash  
author: [株式会社LIFULL](https://convert.docswell.com/user/LIFULL)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/Y79Y3ZKDE3.jpg?width=480
description: シェルスクリプト(主にbash)の内容を浅く見つつ、少し深めの内容まで触れました。
published: April 14, 23
canonical: https://convert.docswell.com/s/LIFULL/KW1WE4-2023-04-14-112307
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/Y79Y3ZKDE3.jpg)

シェルスクリプト
浅めの深堀り
株式会社LIFULL
社内技術勉強会
プラットフォームG 寺井輝
1
1
© LIFULL Co.,Ltd. 本書の無断転載、複製を固く禁じます。


# Page. 2

![Page Image](https://bcdn.docswell.com/page/G786M1R5JD.jpg)

今日の内容
- Shebang の話
- setでオプションをつけられる話
- [ ] と [[ ]] の話
- ファイルディスクリプタの話
※ 以降のシェルスクリプトは全てbashで動かすことを想定しています
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/L7L93QK3ER.jpg)

Shebang の話
Shebang(しばん、しぇばん) はシェルスクリプト一行目に書くおまじない
Shebangに書いた処理系の実行ファイルで実行される
bashなスクリプトだと以下のパターンが多い
#!/bin/bash
or
#!/usr/bin/env bash
これらは何が違うのか、どちらがいいのか問題
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/4EMZD12M7W.jpg)

/bin/bash と /usr/bin/env bash
#!/bin/bash
-
/bin/bash で実行
ほとんどのUNIXベースのOSではデフォルトの場所
必ず指定した実行ファイルを使うので比較的セキュリティが高い(らしい)
追加でパラメータを渡すことが可能
システムによっては実行ファイルの場所が違って動かない場合もある
#!/usr/bin/env bash
-
$PATH を参照して実行可能なファイルを検索して実行
システムやユーザーごとに設定に柔軟に対応できる
移植性が高いことがメリット
追加でパラメータを渡すことができない
実行環境の $PATH によるため意図しない動きが出る可能性はある
(確実に /bin/bash が動く開発環境なら #!/bin/bash でいいんじゃないかな)
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/PER64LMLJ9.jpg)

Shebang の動きをもう少し深堀り
&gt; Shebangに書いた処理系の実行ファイルで実行される
ということはつまり処理系実行ファイルならなんでも動かせたりします
test.sh
test.sh
#!/bin/echo
#!/bin/cat
$ ./test.sh hoge
&gt; hoge
$ ./test.sh hoge.md
&gt; hoge.mdの中身
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/P7XM2WK6JX.jpg)

Shebang に追加パラメータを設定する
#!/bin/bash について
&gt; 追加でパラメータを渡すことが可能
#!/bin/bash -x
(デバッグ行が出力されるオプション)
ただし、明示的に実行ファイルを指定された時には消えてしまうことに注意
test.sh
#!/bin/bash -x
$ bash test.sh
&gt; (xオプションが反映されない)
-&gt; bash なオプションを設定する時は set を使った方がよいかも
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/37KGMV5GED.jpg)

set で実行時のオプションをつけられる話
よく見るsetオプション四天王
-e : エラーがあったら終了
-x : デバッグ行っぽいのを出力
-u : 未定義変数がある時にエラー
-o pipefail: -oはシェルオプションの設定、pipefailだとパイプの左辺失敗時にエラー
set -euxo pipefail
↑ こんな感じで一括で書ける
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/LJ3NYMK5J5.jpg)

set は途中で変更できます
setオプションの - は実は マイナス のことなので +(プラス) もあります
#!/bin/bash
set -x
echo ‘hoge’
set +x
echo ‘hogehoge’
$ ./test.sh
+ echo hoge
hoge
+ set +x
hogehoge
一部だけxオプションで囲ってデバッグなど可能
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/8JDW563YEG.jpg)

[ ] と [[ ]] の話
[]
- コマンドの test と同等
[[ ]]
- bash で拡張されたキーワード
- 拡張正規表現が使えたりパラメータ展開ができる
- &amp;&amp; , || , &lt; , &gt; も使える
先に結論:
実行がbash前提であれば [[ ]] を使っておけば間違いはない
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/VEP9GY4278.jpg)

[ ] と [[ ]] をもう少し詳しく見る
正規表現が使える
#!/bin/bash
x=1223
[ $x =~ ^12*3$ ] &amp;&amp; echo ok
[[ $x =~ ^12*3$ ]] &amp;&amp; echo ok
$ ./test.sh
./test.sh: line 5: [: =~: binary
operator expected
ok
ワイルドカードが使える
#!/bin/bash
x=1223
[ $x == 1*3 ] &amp;&amp; echo &#039;single ok&#039;
[[ $x == 1*3 ]] &amp;&amp; echo &#039;double ok&#039;
$ ./test.sh
double ok
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/27VM6GXX7Q.jpg)

[ ] と [[ ]] をもう少し詳しく見る 2
-n の挙動が微妙に違う
#!/bin/bash
x=1
y=&#039;&#039;
[ -n $x ] &amp;&amp; echo &#039;single not empty1&#039;
[[ -n $x ]] &amp;&amp; echo &#039;double not empty1&#039;
[ -n “$y” ] &amp;&amp; echo &#039;single not empty2&#039;
[[ -n $y ]] &amp;&amp; echo &#039;double not empty2&#039;
[ -n “$z” ] &amp;&amp; echo &#039;single not empty3&#039;
[[ -n $z ]] &amp;&amp; echo &#039;double not empty3&#039;
$ ./test.sh
single not empty1
double not empty1
single not empty2
single not empty3
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/5JGGN8VRJL.jpg)

ファイルディスクリプタ の話
ファイルディスクリプタ: ファイル書き込み用の通信チャネルのようなもの
一般に以下のようになっている
(man bash すると詳しく出てくる)
ファイルディスクリプタ番号
出力先
0
標準入力
1
標準出力
2
標準エラー出力
n
任意の出力先
備考
OSで標準的に番号付けされている
自分で設定可能
つまり...？
$ echo ‘hoge’ &gt; hoge
は標準出力(ファイルディスクリプタ1)を使ってhogeに出力
$ echo ‘hoge’ 2&gt; hoge
は標準エラー出力(ファイルディスクリプタ2)を使ってhogeに出力
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/47QXQ96YJP.jpg)

ファイルディスクリプタが競合する問題を考える
Q. in から一行ずつ読み込んで、それぞれのループで出力するか否かをインタラクティブにやりたい
test.sh
#!/bin/bash
while read -r line; do
read -p &quot;表示する? (y/N): &quot; ans
case &quot;$ans&quot; in
[yY]*) echo $ans;;
*);;
esac
done &lt; &lt;(cat ./in)
in
&lt;
in1
in2
in3
in4
どんな挙動になる？
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/KE46NX4ZJ1.jpg)

ファイルディスクリプタが競合する問題を考える 2
A. 何も表示されません
$ ./test.sh
$
もう少し詳しく見る
test.sh
#!/bin/bash
while read -r line; do
read -p &quot;表示する? (y/N): &quot; ans
echo &quot;line: $line&quot;
echo &quot;ans: $ans&quot;
case &quot;$ans&quot; in
[yY]*) echo $ans;;
*);;
esac
done &lt; &lt;(cat ./in)
$ ./test.sh
line: in1
ans: in2
line: in3
ans: in4
$line と $ans の両方に標準入力の値が入ってしまっている
ファイルディスクリプタ0が競合している状態
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/L71V5N4DJG.jpg)

ファイルディスクリプタが競合する問題を考える 解決案
標準入力用のファイルディスクリプタが被っているので、片方を別のものに指定すればよい
test.sh
#!/bin/bash
while read -r line &lt;&amp;3; do
read -p &quot;表示する? (y/N): &quot; ans
echo &quot;line: $line&quot;
echo &quot;ans: $ans&quot;
case &quot;$ans&quot; in
[yY]*) echo $line;;
*);;
esac
done 3&lt; &lt;(cat ./in)
$ ./test.sh
表示する? (y/N):
line: in1
ans: y
in1
表示する? (y/N):
line: in2
ans: y
in2
表示する? (y/N):
line: in3
ans: y
in3
表示する? (y/N):
line: in4
ans: y
in4
y
y
y
y
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/G7WL54X8J2.jpg)

おまけ: その他 ネタ
bashとzshだと配列のindexがずれるので注意
#!/bin/bash
arr=(a b c)
for i in {0..3}; do
echo &quot;arr[$i] = ${arr[$i]}&quot;
done;
#!/bin/zsh
arr=(a b c)
for i in {0..3}; do
echo &quot;arr[$i] = ${arr[$i]}&quot;
done;
#!/usr/local/bin/fish
ちなみにﬁshも1からだった
set arr a b c
for i in (seq 0 3)
echo &quot;arr[$i] = $arr[$i]&quot;
end
$ ./test.sh
arr[0] = a
arr[1] = b
arr[2] = c
arr[3] =
$ ./test.sh
arr[0] =
arr[1] = a
arr[2] = b
arr[3] = c
$ ./test.sh
./test.sh (line 6): array indices start at 1, not 0.
echo &quot;arr[$i] = $arr[$i]&quot;
^
arr[1] = a
arr[2] = b
arr[3] = c
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/4JZMN26973.jpg)

まとめ
- 実行環境が固定の場合は適切な記載があることが多い
- ファイルディスクリプタの概念
- 特に標準入出力の扱いに注意
17


# Page. 18

![Page Image](https://bcdn.docswell.com/page/YE6N8V2DEV.jpg)

参考リンク
Shebang関連
https://www.baeldung.com/linux/bash-shebang-lines
括弧表記の違いについて
https://genzouw.com/entry/2020/06/09/083836/2041/
ファイルディスクリプタ関連
https://qiita.com/laikuaut/items/e1cc312ffc7ec2c872fc
https://milestone-of-se.nesuke.com/sv-basic/linux-basic/fd-stdinout-pipe-redirect/
18


