代入
$ a='こんにちは、世界'
比較
$ if [ "$a" = "hoge" ]; then echo "yes"; fi
別の文字列を含むか
$ if [[ "$a" == *og* ]]; then echo "yes"; fi
長さ
$ echo $#a
8
n文字目を取得(1始まり)
$ echo $a[1]
こ
部分文字列(n文字目から長さl)
$ echo ${a:2:3}
にちは
部分文字列(n文字目からm文字目。終端含む)
$ echo ${c[2,3]}
んに
部分文字列(n文字目以降)
$ echo ${a:2}
にちは、世界
部分文字列(先頭n文字)
$ echo ${a::2}
こん
部分文字列(末尾n文字)
$ echo ${a: -2}
世界
置換(最初の1個)
(検索文字列の*
はワイルドカード)
$ a='こんにちは、世界。こんにちは、世界'
$ echo ${a/にち/ばん}
こんばんは、世界。こんにちは、世界
置換(全部)
$ echo ${a//にち/ばん}
こんばんは、世界。こんばんは、世界
前後の空白をtrim
$ c=' Hello world '
$ echo "[${${c##[[:space:]]##}%%[[:space:]]##}]"
[Hello world]
${c##xxx}
で文字列cの先頭からパターンxxxにマッチする部分を削除する(最長マッチ)。
${c%%xxx}
で文字列cの末尾からパターンxxxにマッチする部分を削除する(最長マッチ)。
[[:space:]]##
はスペースの1個以上の繰り返し(##
に1個以上の繰り返しという意味がある)。
先頭の空白をtrim
$ echo "[${c##[[:space:]]##}]"
[Hello world ]
末尾の空白をtrim
$ echo "[${${c}%%[[:space:]]##}]"
[ Hello world]
大文字にする
$ b='Hello world'
$ echo ${(U)b}
HELLO WORLD
小文字にする
$ echo ${(L)b}
hello world
ゼロパディング
$ a=1; echo ${(l:4::0:)a}
0001
# 長い場合は切り詰められる
$ a=99999; echo ${(l:4::0:)a}
9999
splitして配列にする
# カンマで分割
s='hoge,moge,sage'
a=(${(s:,:)s})
# コロンで分割したい場合は、他の記号で囲めば良い(下記はスラッシュにした)
s='hoge:moge:sage'
a=(${(s/:/)s})
# 改行で分割
a=(${(f)s})
# \0で分割
a=(${(0)s})
# zshの文法に従って単語に分割する
a=(${(z)s})
join
リテラルでjoin
$ a=(hoge moge sage)
$ echo ${(j:/:)a}
hoge/moge/sage
変数でjoin
$ a=(hoge moge sage)
$ b='/'
$ echo ${(pj:$b:)a}
hoge/moge/sage
改行でjoin
$ a=(hoge moge sage)
$ echo "${(F)a}"
hoge
moge
sage
正規表現でグルーピング
if [[ "ab123cd456" =~ ([0-9]+)[^0-9]+([0-9]+) ]]; then
echo "${MATCH}" # => 123cd456
echo "${match[1]}" # => 123
echo "${match[2]}" # => 456
fi
パターンマッチ判定
$ [[ "$a" == *og* ]] && echo yes
yes
パターンマッチはglobとは異なり*
が.
や/
にもマッチする。
$ [[ ".zshrc" == * ]] && echo yes
yes
パターンマッチでは下記の演算子が使える。#
と##
のおかげで拡張正規表現相当のことはできる。
* 任意の文字列。空文字列にもマッチ
? 任意の1文字
[abc] a b c いずれか
[a-z] aからzまでの1文字
[^abc] a b c以外の1文字
[^a-z] aからzまで以外の1文字にマッチ
<1-100> 1から100までの数
<-> 任意の数
(...) パターンのグループ化
x|y パターンxまたはパターンy
^x パターンx以外。setopt EXTENDED_GLOBが必要
x~y パターンxにマッチし、パターンyにマッチしない。setopt EXTENDED_GLOBが必要
x# パターンxの0回以上の繰り返し。setopt EXTENDED_GLOBが必要。12#は(12)#でなく1(2)#になることに注意
x## パターンxの1回以上の繰り返し。setopt EXTENDED_GLOBが必要。12#は(12)#でなく1(2)#になることに注意
クォート
バックスラッシュでクォート
$ a='a b"c'
$ echo "${(q)a}"
a\ b\"c
シングルクォートでクォート
$ echo "${(qq)a}"
'a b"c'
ダブルクォートでクォート
$ echo "${(qqq)a}"
"a b\"c"
ホームディレクトリを ~ に置換
$ a='/home/aoyama/bin'
$ echo "${(D)a}"
~/bin
$ print -v x -D "/home/aoyama/bin"
$ echo $x
~/bin
(printは標準出力に出力するコマンドだが、オプション-v x
で変数xに代入になる)
~ をホームディレクトリに置換
(e)
が使えるが、変数展開やコマンド置換もされてしまうので注意。
$ a='~/bin'
$ echo "${(e)a}"
~/bin
変数が展開される。
$ a='$SHELL'
$ echo "${(e)a}"
/bin/zsh
コマンド置換もされる。
$ a='$(date)'
$ echo "${(e)a}"
Sat Nov 4 12:18:30 AM JST 2023
リテラル
公式ドキュメント:Quoting
シングルクォート
バックスラッシュによるエスケープは一切効かない。
$ print -r -- '\n'
\n
ダブルクォート
\
'
"
$
!
をバックスラッシュでエスケープできる。\n
\t
は改行・タブにならない。
(!
のエスケープを忘れて履歴展開されてしまうのはやりがちなので注意)
$ print -r -- "\""
"
ドル付きシングルクォート $'...'
\n
で改行、\t
でタブ、\xXX
でASCIIコード、\uxxxx
でユニコードコードポイントなどが使える。
$ print -r -- $'a\nb'
a
b
$ print -r -- $'\x41'
A
$ print -r -- $'\u3042'
あ