0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[シェル] パターンマッチングのオプション

Last updated at Posted at 2024-07-29

パターンマッチングに関するオプションが存在しますが、パス名展開かそれ以外かで異なる場合があります。

例えば、シェルオプション nocaseglob はパス名展開用で、シェルオプション nocasematch はパス名展開以外用です。

参考「Bash Reference Manual
参考「4.3.1 The Set Builtin - Bash Reference Manual
参考「4.3.2 The Shopt Builtin - Bash Reference Manual
参考「5.2 Bash Variables - Bash Reference Manual

パターンマッチングに関しては別記事にしました。

参考「シェルのパターンマッチング - Qiita

0. まとめ

シェルオプション extglob および globasciiranges を除いて、名前に glob を含むオプションはパス名展開用です。

互換モードのバージョンによって一部の挙動が変化する場合があります。
※パス名展開用のオプションを変更してもパス名展開以外には影響しません。
※パス名展開以外用のオプションを変更してもパス名展開には影響しません。

共通:

  • シェルオプション
    • extglob
    • globasciiranges
  • シェル変数
    • LC_ALL
    • LC_COLLATE
    • LC_CTYPE

パス名展開:

  • オプション
    • -f
    • -o noglob
  • シェルオプション
    • dotglob
    • globskipdots
    • failglob
    • nullglob
    • globstar
    • nocaseglob
  • シェル変数
    • GLOBIGNORE

パス名展開以外:

  • シェルオプション
    • nocasematch
    • patsub_replacement

1. 共通

1.1. シェルオプション

シェルオプション 意味
extglob 拡張パターンマッチングを有効化する
globasciiranges パターン [...] の範囲表現を C ロケール扱いにする

※上記のシェルオプションは正規表現には影響しません。

1.1.1. 拡張パターンマッチング

シェルオプション extglob を有効化することで拡張パターンマッチングを利用可能になります。

シェルオプション extglob の影響を受ける場所は以下の通りです:

  • パス名展開
  • case コマンド
  • パラメータ展開
    • パターン削除
      • ${parameter#pattern}
      • ${parameter##pattern}
      • ${parameter%pattern}
      • ${parameter%%pattern}
    • パターン置換
      • ${parameter/pattern/string}
      • ${parameter//pattern/string}
      • ${parameter/#pattern/string}
      • ${parameter/%pattern/string}
      • ${parameter/pattern}
      • ${parameter//pattern}
      • ${parameter/#pattern}
      • ${parameter/%pattern}
    • 大文字小文字変換
      • ${parameter^pattern}
      • ${parameter^^pattern}
      • ${parameter,pattern}
      • ${parameter,,pattern}

条件コマンド [[ expression ]] では常に拡張パターンマッチングを使用可能なため、シェルオプション extglob の影響を受けません。

shopt -s extglob

# 
function f() {

	echo /usr/@(lib)

	case 'foo' in
		@(foo)) echo 'OK' ;;
		*) echo 'NG' ;;
	esac

	local -r parameter='foo bar'
	echo "${parameter/@(foo)/baz}"
	echo "${parameter#@(foo) }"
	echo "${parameter^@(f)}"

}

f
実行結果
/usr/lib
OK
baz bar
bar
Foo bar

1.1.2. ASCII 範囲

パターン [...] の範囲表現はロケールによって動作が変化しますが、シェルオプション globasciiranges を用いることで C ロケール扱いに出来ます。

※シェル変数の値の設定に export は不要ですが、ここでは sort コマンドにも設定を反映させるために export しています。

export LC_COLLATE=en_US.UTF-8
echo -e 'A\nB\na\nb\n' | sort | xargs

shopt -s globasciiranges
echo /usr/li[A-B]
[[ 'b' == [A-B] ]] && echo 'OK' || echo 'NG'

shopt -u globasciiranges
echo /usr/li[A-B]
[[ 'b' == [A-B] ]] && echo 'OK' || echo 'NG'
実行結果
a A b B
/usr/li[A-B]
NG
/usr/lib
OK

1.2. シェル変数

シェル変数 意味
LC_ALL LANG および他の LC_ 変数の値を上書きする
LC_COLLATE パターン [...] の範囲表現、等価クラス [=c=]、照合シンボル [.symbol.] および照合順序の動作を決定する
LC_CTYPE 文字の解釈と文字クラス [:class:] の動作を決定する

※コマンド実行時に直接 1 行で NAME=value command arguments のようにシェル変数の値を変更した場合、command の引数の arguments に含まれるパターンに設定が反映されないため注意。
※シェル変数の値の設定に export不要です。
※上記のシェル変数は正規表現の一部にも影響します。

1.2.1. 照合

※シェル変数の値の設定に export は不要ですが、ここでは sort コマンドにも設定を反映させるために export しています。

shopt -u globasciiranges

export LC_COLLATE=C.UTF-8
echo -e 'A\nB\na\nb\n' | sort | xargs
echo /usr/li[A-B]
[[ 'b' == [A-B] ]] && echo 'OK' || echo 'NG'

export LC_COLLATE=en_US.UTF-8
echo -e 'A\nB\na\nb\n' | sort | xargs
echo /usr/li[A-B]
[[ 'b' == [A-B] ]] && echo 'OK' || echo 'NG'
実行結果
A B a b
/usr/li[A-B]
NG
a A b B
/usr/lib
OK

1.2.2. 文字タイプ

touch LC_CTYPE=C.UTF-8
[[ 'あ' == [[:alpha:]] ]] && echo 'OK' || echo 'NG'
echo [[:alpha:]]

LC_CTYPE=C
[[ 'あ' == [[:alpha:]] ]] && echo 'OK' || echo 'NG'
echo [[:alpha:]]
実行結果
OK
あ
NG
[[:alpha:]]

2. パス名展開

2.1. オプション

オプション 意味
-f
-o noglob
パス名展開を無効化する

※上記のオプションはパス名展開以外には影響しません。
※上記のオプションは正規表現には影響しません。

2.1.1. 無効化

# 
set +f
echo /usr/li?

set -f
echo /usr/li?

# 
set +o noglob
echo /usr/li?

set -o noglob
echo /usr/li?
実行結果
/usr/lib
/usr/li?
/usr/lib
/usr/li?

2.2. シェルオプション

シェルオプション 意味
dotglob ファイル名 . および .. を除いて、. で始まるファイル名と暗黙的に一致するようにする
globskipdots ファイル名 . および .. はパターンと一致しないようにする
failglob パターンと一致しない場合はエラーにする
nullglob パターンと一致しない場合は空文字列にする
globstar パターン ** を有効化する
nocaseglob 大文字小文字を区別しない

※後述のシェル変数 GLOBIGNORE はシェルオプション dotglob に影響します。
※後述のシェル変数 GLOBIGNORE はシェルオプション globskipdots に影響します。
※上記のシェルオプションはパス名展開以外には影響しません。
※上記のシェルオプションは正規表現には影響しません。

2.2.1. . で始まるファイル名

ファイル名 . および .. を除いて、. で始まるファイル名を扱う場合は以下のことに注意が必要です:

  • シェルオプション dotglob無効の場合、 . で始まるパターンと明示的に一致する
    • ?[.] 等で始まるパターンと暗黙的に一致しない
  • シェルオプション dotglob有効の場合、パターンと暗黙的に一致する
    • ?[.] 等で始まるパターンとも暗黙的に一致する

ファイル名 . および .. を扱う場合は以下のことに注意が必要です:

  • シェルオプション globskipdots有効の場合、パターンと常に一致しない
    • . で始まるパターンとも明示的に一致しない
  • シェルオプション globskipdots無効の場合、. で始まるパターンと明示的に一致する
    • シェルオプション dotglob が有効でも、?[.] 等で始まるパターンと暗黙的に一致しない
# 
shopt -u dotglob
echo ~/.ss? | basename "$(cat)"
echo ~/?ssh | basename "$(cat)"

shopt -s dotglob
echo ~/.ss? | basename "$(cat)"
echo ~/?ssh | basename "$(cat)"

# 
shopt -s globskipdots
echo /.[.] | basename "$(cat)"
echo /[.]. | basename "$(cat)"

shopt -u globskipdots
echo /.[.] | basename "$(cat)"
echo /[.]. | basename "$(cat)"
実行結果
.ssh
?ssh
.ssh
.ssh
.[.]
[.].
..
[.].

2.2.2. 不一致の扱い

shopt -u failglob
(echo /usr/?) 2>/dev/null || echo 'NG'

shopt -s failglob
(echo /usr/?) 2>/dev/null || echo 'NG'
実行結果
/usr/?
NG
shopt -u failglob

shopt -u nullglob
echo /usr/?

shopt -s nullglob
echo /usr/?
実行結果
/usr/?

2.2.3. パターン **

mkdir -p directory
touch foo directory/foo

# 
shopt -u globstar
echo **/foo

shopt -s globstar
echo **/foo
実行結果
directory/foo
directory/foo foo

2.2.4. 大文字小文字の区別

shopt -u nocaseglob
echo /usr/LI?

shopt -s nocaseglob
echo /usr/LI?
実行結果
/usr/LI?
/usr/lib

2.3. シェル変数

シェル変数 意味
GLOBIGNORE 無視するファイル名の一覧

※コマンド実行時に直接 1 行で NAME=value command arguments のようにシェル変数の値を変更した場合、command の引数の arguments に含まれるパターンに設定が反映されないため注意。
※シェル変数の値の設定に export不要です。
※シェル変数 GLOBIGNORE は前述のシェルオプション dotglob に影響します。
※シェル変数 GLOBIGNORE は前述のシェルオプション globskipdots に影響します。
※上記のシェル変数はパス名展開以外には影響しません。
※上記のシェル変数は正規表現には影響しません。

2.3.1. 無視するファイル名

2.3.1.1. 基本

シェル変数 GLOBIGNORE で無視するファイル名を指定出来ます。

コロン : 区切りで複数のパターンを設定可能です。

※シェル変数 GLOBIGNORE相対パスを設定した場合、カレントディレクトリによって動作が異なるため注意。
※シェル変数 GLOBIGNORE空の値を設定した場合、設定していない扱いになります。

GLOBIGNORE=/usr/lib*
echo /usr/li?

unset GLOBIGNORE
echo /usr/li?
実行結果
/usr/li?
/usr/lib

2.3.1.2. ファイル名 ... および . で始まるファイル名

ファイル名 ... および . で始まるファイル名に関しては以下のことに注意が必要です:

  • ファイル名 . および ..必ず無視される
    • 前述のシェルオプション globskipdots が無効でも必ず無視される
  • 前述のシェルオプション dotglob有効になり、. で始まるファイル名は無視されなくなる
    • . で始まるファイル名を無視したい場合はシェル変数 GLOBIGNORE にパターン .* を追加する
      • ※シェル変数 GLOBIGNORE にパターン .* を追加した場合、. で始まるファイル名と明示的に一致しなくなるため注意
      • ※シェル変数 GLOBIGNORE相対パスを設定した場合、カレントディレクトリによって動作が異なるため注意
shopt -u globskipdots

# 
GLOBIGNORE=/usr/lib*
echo /usr/li?
echo ~/?ssh | basename "$(cat)"
echo /.[.] | basename "$(cat)"

unset GLOBIGNORE
echo /usr/li?
echo ~/?ssh | basename "$(cat)"
echo /.[.] | basename "$(cat)"
実行結果
/usr/li?
.ssh
.[.]
/usr/lib
?ssh
..

2.3.1.3. シェルオプション dotglob に対する影響

シェル変数 GLOBIGNORE は前述のシェルオプション dotglob に影響する場合があります:

  • シェル変数 GLOBIGNORE空でない値が設定されると、前述のシェルオプション dotglob有効になる
  • シェル変数 GLOBIGNOREunset されると、前述のシェルオプション dotglob無効になる
  • シェル変数 GLOBIGNORE空の値を設定しても、前述のシェルオプション dotglob有効にも無効にも変更されない
shopt -u dotglob
shopt dotglob || :
GLOBIGNORE=/usr/lib*
shopt dotglob || :

shopt -s dotglob
shopt dotglob || :
unset GLOBIGNORE
shopt dotglob || :
実行結果
dotglob         off
dotglob         on
dotglob         on
dotglob         off

2.3.1.4. 他のオプションから受ける影響

シェル変数 GLOBIGNORE は前述のシェルオプションの一部の影響を受けます。

シェルオプション あり なし
extglob
globasciiranges
dotglob
globskipdots
failglob
nullglob
globstar
nocaseglob

※シェルオプション globstar が有効でも、シェル変数 GLOBIGNORE の値でパターン ** は特別な意味を持たず、パターン * と同じ意味になるため注意。
※シェル変数 GLOBIGNORE はシェルオプション dotglob および globskipdots に影響しますが、シェルオプション dotglob および globskipdots はシェル変数 GLOBIGNORE に影響しません。
※シェル変数 GLOBIGNORE に空でない値を設定後に手動でシェルオプション dotglob を無効化した場合も、シェル変数 GLOBIGNORE の値は . で始まるファイル名と暗黙的に一致します。

前述の LC_ 変数はシェル変数 GLOBIGNORE に影響します。

2.3.1.5. GLOBIGNORE=.*shopt -u dotglob の違い

GLOBIGNORE=.* および shopt -u dotglob はどちらも . で始まるファイル名をパス名展開で無視するための設定ですが、以下のような違いがあります:

  • GLOBIGNORE=.*
    • . で始まるファイル名はパターンと明示的に一致しない
    • カレントディレクトリ直下のファイルのみに影響する
  • shopt -u dotglob
    • . で始まるファイル名はパターンと暗黙的に一致しない
    • . で始まるファイル名はパターンと明示的に一致する
    • カレントディレクトリ直下以外のファイルにも影響する

3. パス名展開以外

3.1. シェルオプション

シェルオプション 意味
nocasematch 大文字小文字を区別しない
patsub_replacement パターン置換 ${parameter/pattern/string}string 内の & を有効化する

※上記のシェルオプションはパス名展開には影響しません。
※シェルオプション nocasematch は正規表現にも影響します。
※シェルオプション patsub_replacement は正規表現には影響しません。

3.1.1. 大文字小文字の区別

シェルオプション nocasematch を有効化することで大文字小文字を区別しなくなります。

シェルオプション nocasematch の影響を受ける場所は以下の通りです:

  • case コマンド
  • 条件コマンド [[ expression ]]
  • パラメータ展開
    • パターン置換
      • ${parameter/pattern/string}
      • ${parameter//pattern/string}
      • ${parameter/#pattern/string}
      • ${parameter/%pattern/string}
      • ${parameter/pattern}
      • ${parameter//pattern}
      • ${parameter/#pattern}
      • ${parameter/%pattern}
  • プログラム補完 コマンド
    • compgen -X filterpat
    • complete -X filterpat
# 
function f() {

	case 'foo' in
		FOO) echo 'OK' ;;
		*) echo 'NG' ;;
	esac

	[[ 'foo' == FOO ]] && echo 'OK' || echo 'NG'

	local -r parameter='foo bar'
	echo "${parameter/FOO/baz}"

}

# 
shopt -u nocasematch
f

shopt -s nocasematch
f
実行結果
NG
NG
foo bar
OK
OK
baz bar

ちなみに、パラメータ展開のパターン削除および大文字小文字変換は影響を受けないため注意:

  • パラメータ展開
    • パターン削除
      • ${parameter#pattern}
      • ${parameter##pattern}
      • ${parameter%pattern}
      • ${parameter%%pattern}
    • 大文字小文字変換
      • ${parameter^pattern}
      • ${parameter^^pattern}
      • ${parameter,pattern}
      • ${parameter,,pattern}

パターン削除で nocasematch を使用したい場合、パターン置換や正規表現等に書き換えます。

※シェルオプション nocasematch はパターンマッチングだけでなく正規表現にも影響します。

参考「[シェル] パターン置換 "${parameter/pattern}" を用いたパターン削除 - Qiita

3.1.2. パターン置換の &

# 
function f() {

	local -r parameter='foo bar'
	echo "${parameter/foo/&}"
	echo "${parameter/foo/\&}"
	echo "${parameter/foo/'&'}"

}

#  
shopt -s patsub_replacement
f

shopt -u patsub_replacement
f
実行結果
foo bar
& bar
& bar
& bar
& bar
& bar

4. 互換モード

シェル変数 BASH_COMPAT で互換モードのバージョンを指定可能です。

※互換モードのシェルオプションは廃止予定です。

バージョン シェルオプション
5.1 (なし)
4.2 compat42

パターンマッチングに影響する互換性レベル:

  • バージョン 5.1
    • コマンド置換 $(command) は解析時に拡張パターンマッチングが有効の扱いにする
  • バージョン 4.2
    • 二重引用符で囲まれたパターン置換 ${parameter/pattern/string} における置換文字列 string は引用符の削除を行わない

参考「[Bash] 互換モード - Qiita
参考「6.12 Shell Compatibility Mode - Bash Reference Manual

4.1. コマンド置換 $(command) における拡張パターンマッチング

違い:

  • バージョン 5.2 以降
    • 拡張パターンマッチングが無効のときにコマンド置換 $(command) で拡張パターンを用いると、未実行であっても解析時にエラーが発生する
  • バージョン 5.1 以前
    • コマンド置換 $(command) は解析時に拡張パターンマッチングが有効の扱いにする
    • 拡張パターンマッチングが無効のときにコマンド置換 $(command) で拡張パターンを用いても、それが実行されるまでに拡張パターンマッチングが有効化されればエラーは発生しない

※コマンド置換 `command` には影響しません。
※パラメータ展開の拡張パターンには影響しません。

# 
unset BASH_COMPAT

shopt -s extglob
function f() {

	echo "$(echo /usr/@(lib))"

	echo "$(case 'foo' in @(foo)) echo 'OK' ;; *) echo 'NG' ;; esac)"

}

shopt -s extglob
f

# 
BASH_COMPAT=5.1

shopt -u extglob
function g() {

	echo "$(echo /usr/@(lib))"

	echo "$(case 'foo' in @(foo)) echo 'OK' ;; *) echo 'NG' ;; esac)"

}

shopt -s extglob
g
実行結果
/usr/lib
OK
/usr/lib
OK

4.2. 二重引用符で囲まれたパターン置換 ${parameter/pattern/string} における置換文字列 string

違い:

  • バージョン 4.3 以降
    • 引用符の削除を行う
  • バージョン 4.2 以前
    • 引用符の削除を行わない
# 
function f() {

	local -r parameter='foo bar'
	echo "${parameter/foo/'baz'}"

}

#  
unset BASH_COMPAT
f

BASH_COMPAT=4.2
f
# 
function f() {

	local -r parameter='foo bar'
	echo "${parameter/foo/'baz'}"

}

#  
shopt -u compat42
f

shopt -s compat42
f
実行結果
baz bar
'baz' bar

二重引用符内だけでなく、ヒアドキュメント内も影響します。

# 
function f() {

	local -r parameter='foo bar'
	cat <<-EOF
		${parameter/foo/'baz'}
	EOF

}

#  
unset BASH_COMPAT
f

BASH_COMPAT=4.2
f
# 
function f() {

	local -r parameter='foo bar'
	cat <<-EOF
		${parameter/foo/'baz'}
	EOF

}

#  
shopt -u compat42
f

shopt -s compat42
f
実行結果
baz bar
'baz' bar
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?