「シェルスクリプトの基礎 - 変数」の版間の差分

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動
166行目: 166行目:
  FILES=`ls`
  FILES=`ls`
  echo "$FILES"
  echo "$FILES"
</source>
<br><br>
== 変数展開機能 ==
変数展開の仕組みを利用すると、変数に格納された文字列を置換、変数の存在を確認、変数の初期値の指定等ができる。<br>
<br>
==== パターン照合演算子 ====
下表に示すように、変数展開の構文を使用すると、変数に格納された文字列の一部を置換した文字列を作成することができる。<br>
また、パターン部分において、ワイルドカード(*、?、[a-z]等)が使用できる。<br>
<center>
{| class="wikitable"
|-
! 構文 !! 意味
|-
| ${変数/パターン/置換文字列} || パターンに一致する部分を置換文字列に置き換える(1つだけ)
|-
| ${変数//パターン/置換文字列} || パターンに一致する部分を置換文字列に置き換える(すべて)
|-
| ${変数#パターン} || 先頭から最短一致でパターンに一致する部分を取り除く
|-
| ${変数##パターン} || 先頭から最長一致でパターンに一致する部分を取り除く
|-
| ${変数%パターン} || 末尾から最短一致でパターンに一致する部分を取り除く
|-
| ${変数%%パターン} || 末尾から最長一致でパターンに一致する部分を取り除く
|}
</center>
<br>
* 最初に一致する文字列のみ置換する。
<source lang="sh">
# 実行
X=aaabbbccc
Y=${X/b/B}
echo $Y
# 出力
aaaBbbccc
</source>
<br>
* パターンに一致する文字列を全て置換する。
<source lang="sh">
# 実行
X=aaabbbccc
Y=${X//b/B}
echo $Y
# 出力
aaaBBBccc
</source>
<br>
sedコマンドと同様の結果を、シェルスクリプトの機能だけで実現できていることがわかる。<br>
<source lang="sh">
X=aaabbbccc
Y=$(echo $X | sed -e 's/bbb/BBB/g')
</source>
<br>
* フルパスからbasenameを取り出す。
*: 以下の例では、/aaa/bbb/cccという絶対パスから、basenameのcccを抽出している。
*: */というパターンで、先頭から最長一致させて、/aaa/bbb/を取り除いている。
<source lang="sh">
# 実行
X=/aaa/bbb/ccc
Y=${X##*/}
echo $Y
# 出力
ccc
</source>
<br>
また、basenameを取得する場合、一般的に、basenameコマンドを使用した方が簡単である。<br>
<source lang="sh">
basename $X
</source>
<br>
* フルパスからdirnameを取り出す。
*: 以下の例では、/aaa/bbb/cccという絶対パスから、ディレクトリ名の/aaa/bbbを抽出している。
*: /*というパターンで、末尾から最短一致させて、/cccを取り除いている。
<source lang="sh">
# 実行
X=/aaa/bbb/ccc
Y=${X%/*}
echo $Y
# 出力
/aaa/bbb
</source>
<br>
また、ディレクトリ名を取得する場合、一般的に、dirnameコマンドを使用した方が簡単である。<br>
<source lang="sh">
dirname $X
</source>
<br>
* '#'以降のコメントを削除する。
*: #*というパターンで、末尾から最長一致させて、変数LINEの#以降の部分を削除している。
<source lang="sh">
# 実行
LINE="aaa bbb # This is a comment"
LINE=${LINE%%#*}
echo $LINE
# 出力
aaa bbb
</source>
<br>
==== 初期値 ====
<center>
{| class="wikitable"
|-
! 構文 !! 意味
|-
| ${変数:-word} || 変数が未定義の時、wordを返す。
|-
| ${変数:=word} || 変数が未定義の時、変数にwordを代入して返す。
|-
| ${変数:?}<br>${変数:?word} || 変数が未定義の時、エラーを表示する。
|-
| ${変数:+word} || 変数が定義されている時、wordを返す。
|}
</center>
* ${変数:-word}
*: 例えば、<code>X=${COUNT:-0}</code>と記述すると、変数<code>X</code>の値は変数<code>COUNT</code>の値が無ければ0を返す。
*: つまり、変数<code>COUNT</code>の初期値を0とみなして参照する。
*: <br>
*: この構文は、コマンドライン引数が省略された場合、初期値を設定するために使用できる。
*: 例えば、<code>FILENAME=${1:-input.txt}</code>とすると、変数<code>FILENAME</code>の値は、第1パラメータで指定された値または初期値のinput.txtとなる。
<br>
* ${変数:=word}
*: 例えば、X=${COUNT:=0}と記述すると、変数COUNTの値が無ければ、変数Xおよび変数COUNTに0を代入する。
*: ただし、変数に代入するため、コマンドライン引数や関数の引数の$1を参照する場合には、この方法は使用できない。
<br>
* ${変数:?word}
*: 例えば、以下のように記述すると、変数COUNTの値が無ければエラーを出力して終了する。
<source lang="sh">
# 実行
echo ${COUNT:?}
# 出力
-bash: count: パラメータが null または設定されていません
</source>
<br>
?の後ろに表示するメッセージを指定することもできる。<br>
<source lang="sh">
# 実行
echo ${COUNT:?パラメータが設定されていません}
# 出力
-bash: count: パラメータが設定されていません
</source>
<br>
* ${変数:+word}
*: 変数に値が代入されている場合、代わりにwordの値を返す。
*: 例えば、${COUNT:+1}は、変数COUNTが定義されていたら1と評価される。
<source lang="sh">
# 実行
COUNT=9999
echo ${COUNT:+1}
# 出力
1
</source>
<br>
<source lang="sh">
# 実行
COUNT=9999
unset COUNT
echo ${COUNT:+1}
# 出力
何も表示されない
</source>
<br>
==== 位置指定で部分文字列を抽出する ====
<center>
{| class="wikitable"
|-
! 構文 !! 意味
|-
| ${変数:offset} || offsetで指定した位置から末尾までの文字列を抽出する。
|-
| ${変数:offset:length} || offsetで指定した位置からlength分の文字列を抽出する。
|}
</center>
<br>
<source lang="sh">
# 実行
HOGE=ABCDEFGHIJ
echo ${HOGE:3}
# 出力
DEFGHIJ
</source>
<br>
<source lang="sh">
# 実行
HOGE=ABCDEFGHIJ
echo ${HOGE:3:4}
# 出力
DEFG
</source>
<br>
offsetやlength に負の値を指定して、末尾から文字列を抽出することもできる。<br>
ただし、offsetの前に1つ以上のスペースが必要である。(スペースを入れないと、${変数:-word}という形で初期値が指定されたとみなされる)<br>
<source lang="sh">
# 実行
HOGE=ABCDEFGHIJ
echo ${HOGE: -3}
# 出力
HIJ
</source>
<br>
<source lang="sh>
# 実行
HOGE=ABCDEFGHIJ
echo ${HOGE: -5:-2}
# 出力
FGH
  </source>
  </source>
<br><br>
<br><br>

2020年10月6日 (火) 14:32時点における版

概要



変数の定義と参照

変数へ値を代入する時は$を付けず、変数を参照するときは$を付ける。

 #!/bin/sh
 
 name=Michael        # 変数の定義
 echo Hello $name    # 変数の参照
 echo "Hello $name"  # ダブルクォーテーションは変数を展開する
 echo 'Hello $name'  # シングルクォーテーションは変数を展開しない


# 出力
Hello Michael
Hello Michael
Hello $name


未定義の変数を参照すると、空文字列と同様に扱われる。(エラーにはならない)

 #!/bin/sh
 
 echo "Hello $name !"


# 出力
Hello  !



定数

以下のように実行すると、指定した変数や関数に対する代入、unsetができなくなる。

 readonly var      # 変数varをreadonlyにする
 readonly -a arr   # 配列arrをreadonlyにする
 readonly -f func  # 関数funcをreadonlyにする


以下のように、変数の定義と同時にreadonlyを指定することも可能である。

 readonly USERNAME="Mike"


以下の例では、変数MAX_SIZEを100で初期化した後、200という値を代入しようとしている。
変数MAX_SIZEは定数化されているので、代入しようとした場合はエラーになる。

 #!/bin/bash
 
 readonly MAX_SIZE=100
 MAX_SIZE=200


# 出力
./sample.sh: 行 4: MAX_SIZE: 読み取り専用の変数です



変数の値の確認

test[ ... ]で使用できる演算子には、以下のようなものがある。

  • -z 文字列
    文字列の長さが0の場合に真
  • -n 文字列
    文字列の長さが0でない場合に真


変数名にダブルクォーテーションを付けて値を展開して、上記の演算子でその文字列の長さをチェックすることにより、
変数に値が代入されている(または、代入されていない)ことを確認することができる。

変数に値が代入されていることを確認する

以下の例では、変数NAMEの値がセットされているか調べている。

 #!/bin/bash
 
 if [ -n "$NAME" ]; then
    echo $NAME
 fi


変数に値が代入されていないことを確認する

以下の例では、変数NAMEの値がセットされていないか調べている。

 #!/bin/bash
 
 if [ -z "$NAME" ]; then
    echo 'NAME is not set'
 fi


# 出力
NAME is not set



数値の演算

加算 / 減算

変数の値に対して、加算および減算を行うには以下のように記述する。

 #!/bin/bash
 
 val=100
 let val=$val+200
 echo $val

または

 #!/bin/bash
 
 val=100
 val=$(($val+200))
 echo $val


# 出力
300


ランダムな数値の取得

Bashのシェル変数$RANDOMを参照すると、0~32767の範囲のランダムな整数を取得することができる。

 #!/bin/bash
 
 echo $RANDOM


# 出力
27591


文字列の連結

複数の変数を連結するには、以下のように続けて記述する。

 #!/bin/sh
 
 STR1="Shell script"
 STR2="is intersting!"
 
 STR=$STR1$STR2
 
 echo $STR


また、以下のように変数を{}で括る。

 #!/bin/sh
 
 STR1="Shell script"
 STR="${STR1} is intersting!!"
 
 echo $STR



コマンドの実行結果を変数に代入する

lsgrepfind等のコマンドの実行結果を変数に代入するには、以下のように記述する。

変数=$(コマンド)
   または
変数=`コマンド`


以下の例では、lsコマンドの実行結果を変数FILESに代入して、echoで出力している。

 #!/bin/sh
 
 FILES=$(ls)
 echo "$FILES"

または

 #!/bin/sh
 
 FILES=`ls`
 echo "$FILES"



変数展開機能

変数展開の仕組みを利用すると、変数に格納された文字列を置換、変数の存在を確認、変数の初期値の指定等ができる。

パターン照合演算子

下表に示すように、変数展開の構文を使用すると、変数に格納された文字列の一部を置換した文字列を作成することができる。
また、パターン部分において、ワイルドカード(*、?、[a-z]等)が使用できる。

構文 意味
${変数/パターン/置換文字列} パターンに一致する部分を置換文字列に置き換える(1つだけ)
${変数//パターン/置換文字列} パターンに一致する部分を置換文字列に置き換える(すべて)
${変数#パターン} 先頭から最短一致でパターンに一致する部分を取り除く
${変数##パターン} 先頭から最長一致でパターンに一致する部分を取り除く
${変数%パターン} 末尾から最短一致でパターンに一致する部分を取り除く
${変数%%パターン} 末尾から最長一致でパターンに一致する部分を取り除く


  • 最初に一致する文字列のみ置換する。
 # 実行
 X=aaabbbccc
 Y=${X/b/B}
 echo $Y
 
 # 出力
 aaaBbbccc


  • パターンに一致する文字列を全て置換する。
 # 実行
 X=aaabbbccc
 Y=${X//b/B}
 echo $Y
 
 # 出力
 aaaBBBccc


sedコマンドと同様の結果を、シェルスクリプトの機能だけで実現できていることがわかる。

 X=aaabbbccc
 Y=$(echo $X | sed -e 's/bbb/BBB/g')


  • フルパスからbasenameを取り出す。
    以下の例では、/aaa/bbb/cccという絶対パスから、basenameのcccを抽出している。
    */というパターンで、先頭から最長一致させて、/aaa/bbb/を取り除いている。
 # 実行
 X=/aaa/bbb/ccc
 Y=${X##*/}
 echo $Y
 
 # 出力
 ccc


また、basenameを取得する場合、一般的に、basenameコマンドを使用した方が簡単である。

 basename $X


  • フルパスからdirnameを取り出す。
    以下の例では、/aaa/bbb/cccという絶対パスから、ディレクトリ名の/aaa/bbbを抽出している。
    /*というパターンで、末尾から最短一致させて、/cccを取り除いている。
 # 実行
 X=/aaa/bbb/ccc
 Y=${X%/*}
 echo $Y
 
 # 出力
 /aaa/bbb


また、ディレクトリ名を取得する場合、一般的に、dirnameコマンドを使用した方が簡単である。

 dirname $X


  • '#'以降のコメントを削除する。
    #*というパターンで、末尾から最長一致させて、変数LINEの#以降の部分を削除している。
 # 実行
 LINE="aaa bbb # This is a comment"
 LINE=${LINE%%#*}
 echo $LINE
 
 # 出力
 aaa bbb


初期値

構文 意味
${変数:-word} 変数が未定義の時、wordを返す。
${変数:=word} 変数が未定義の時、変数にwordを代入して返す。
${変数:?}
${変数:?word}
変数が未定義の時、エラーを表示する。
${変数:+word} 変数が定義されている時、wordを返す。
  • ${変数:-word}
    例えば、X=${COUNT:-0}と記述すると、変数Xの値は変数COUNTの値が無ければ0を返す。
    つまり、変数COUNTの初期値を0とみなして参照する。

    この構文は、コマンドライン引数が省略された場合、初期値を設定するために使用できる。
    例えば、FILENAME=${1:-input.txt}とすると、変数FILENAMEの値は、第1パラメータで指定された値または初期値のinput.txtとなる。


  • ${変数:=word}
    例えば、X=${COUNT:=0}と記述すると、変数COUNTの値が無ければ、変数Xおよび変数COUNTに0を代入する。
    ただし、変数に代入するため、コマンドライン引数や関数の引数の$1を参照する場合には、この方法は使用できない。


  • ${変数:?word}
    例えば、以下のように記述すると、変数COUNTの値が無ければエラーを出力して終了する。
 # 実行
 echo ${COUNT:?}
 
 # 出力
 -bash: count: パラメータが null または設定されていません


?の後ろに表示するメッセージを指定することもできる。

 # 実行
 echo ${COUNT:?パラメータが設定されていません}
 
 # 出力
 -bash: count: パラメータが設定されていません


  • ${変数:+word}
    変数に値が代入されている場合、代わりにwordの値を返す。
    例えば、${COUNT:+1}は、変数COUNTが定義されていたら1と評価される。
 # 実行
 COUNT=9999
 echo ${COUNT:+1}
 
 # 出力
 1


 # 実行
 COUNT=9999
 unset COUNT
 echo ${COUNT:+1}
 
 # 出力
 何も表示されない


位置指定で部分文字列を抽出する

構文 意味
${変数:offset} offsetで指定した位置から末尾までの文字列を抽出する。
${変数:offset:length} offsetで指定した位置からlength分の文字列を抽出する。


 # 実行
 HOGE=ABCDEFGHIJ
 echo ${HOGE:3}
 
 # 出力
 DEFGHIJ


 # 実行
 HOGE=ABCDEFGHIJ
 echo ${HOGE:3:4}
 
 # 出力
 DEFG


offsetやlength に負の値を指定して、末尾から文字列を抽出することもできる。
ただし、offsetの前に1つ以上のスペースが必要である。(スペースを入れないと、${変数:-word}という形で初期値が指定されたとみなされる)

 # 実行
 HOGE=ABCDEFGHIJ
 echo ${HOGE: -3}
 
 # 出力
 HIJ


 # 実行
 HOGE=ABCDEFGHIJ
 echo ${HOGE: -5:-2}
 
 # 出力
 FGH