fishのシェルスクリプトで外部コマンドを利用せずに文字列操作を行う場合のメモ。
他シェルの場合はParameter expansionによる文字列操作機能があるがfishの場合はどうすれば良いのかを調べてみた。
ドキュメント https://fishshell.com/docs/current/index.html#expand を確認するもParameter expansionによる該当機能は無さそう。
しかしながら代わりにstringなるビルトインコマンドが存在する。
stringコマンドには文字列の置換、結合、分割、トリム、部分文字列化、エスケープ、マッチそして文字数取得機能があり、 置換、マッチについては正規表現が利用可能。利用可能な正規表現構文は改訂版Perl互換正規表現(PCRE2)
fishやstringコマンドに限った話ではないが、コマンドに与える文字列がハイフンから始まっているとオプションとして認識されエラーになる。 そのような可能性がある文字列を処理する際は以下のようにハイフン二つで表されるオプションの解析終端子を明示的指定する。
set -l str "-abcdefg"
string length -- $str
置換
replace
サブコマンドはリテラル文字列または正規表現で指定されたパターンの置換を行う。
string replace [(-a | --all)] [(-i | --ignore-case)] [(-r | --regex)]
[(-q | --quiet)] PATTERN REPLACEMENT [STRING...]
単一置換
yellow
をblue
へ置換。
string replace yellow blue 'red green yellow'
red green blue
全置換
全てのハイフンをアンダースコアへ置換。
string replace -a - _ RED-GREEN-BLUE
RED_GREEN_BLUE
大文字小文字を無視
大文字小文字を無視してyellow
をblue
へ置換。
string replace -ia yellow blue 'RED GREEN YELLOW yellow Yellow'
RED GREEN blue blue blue
正規表現で置換
全ての大文字を削除する。
string replace -ra '[[:upper:]]' '' 'REDred GREENgreen BLUEblue'
red green blue
後方参照を利用した置換
キーと値を入れ替える
string replace -ra '([^,=]+)=([^,=]+)' '$2=$1' 'key1=value1,key2=value2'
value1=key1,value2=key2
結合
join
サブコマンドは渡された文字列リストを指定のセパレータで連結する。
string join [(-q | --quiet)] SEP [STRING...]
セパレータで結合
全ての要素を/
で結合。
string join / path to somewhere
path/to/somewhere
分割
split
サブコマンドは渡された文字列を指定のいセパレータで分割しリスト化する。
string split [(-m | --max) MAX] [(-r | --right)] [(-q | --quiet)] SEP
[STRING...]
分割してリスト化
文字列を/
で分割。
string split / 'path/to/foo/bar'
path
to
foo
bar
左端から限定分割
/
による分割を2回に限定し左端からリスト化
string split -m2 / 'path/to/foo/bar'
path
to
foo/bar
右端から限定分割
/
による分割を2回に限定し右端からリスト化
string split -rm2 / 'path/to/foo/bar'
path/to
foo
bar
トリム
trim
サブコマンドは空白、または指定の文字を対象文字列の端から取り除く。
string trim [(-l | --left)] [(-r | --right)] [(-c | --chars CHARS)]
[(-q | --quiet)] [STRING...]
両端トリム
両端のスペースを取り除く。
echo This is an (string trim ' apple ').
This is an apple.
左端トリム
左端のスペースを取り除く。
echo This is an (string trim -l ' apple ').
This is an apple .
右端トリム
右端のスペースを取り除く。
echo This is an (string trim -r ' apple ').
This is an apple.
任意文字のトリム
*
を両端から取り除く。
echo This is an (string trim -c '*' '****apple****').
This is an apple.
部分文字列化
sub
サブコマンドは対象文字列中から部分文字列を取得する。
string sub [(-s | --start) START] [(-l | --length) LENGTH] [(-q | --quiet)]
[STRING...]
n文字目以降を取得
2文字目以降を取得。
string sub -s 2 'abcdefg'
bcdefg
n文字目以降m文字分を取得
2文字目以降の3文字分を取得。
string sub -s 2 -l 3 'abcdefg'
bcd
エスケープ
escape
サブコマンドは要エスケープな文字をエスケープする。
string escape [(-n | --no-quoted)] [STRING...]
エスケープする
クォート可能な場合。
string escape "~*()"
'~*()'
クォート不可な場合。
string escape "~*()'"
\~\*\(\)\'
クォートなしでエスケープする
string escape -n "~*()"
\~\*\(\)
マッチ
match
サブコマンドはglob/正規表現によるパターンに一致するかどうか判定する。
判定結果は終了ステータスで返され0が一致、それ以外は不一致を表す。
また一致した場合は戻り値に一致した文字列または位置が返される。
string match [(-a | --all)] [(-i | --ignore-case)] [(-r | --regex)]
[(-n | --index)] [(-q | --quiet)] [(-v | --invert)] PATTERN [STRING...]
globによるマッチ
string match 'app*' apple; echo $status
apple
0
string match 'app?e' apple; echo $status
apple
0
正規表現によるマッチ
string match -r '\d{10}' 'First number is 0123456789'; echo $status
0123456789
0
グループ化されたマッチ結果
string match -r '(\d{2}):(\d{2}):(\d{2})' '08:10:30'
08:10:30
08
10
30
正規表現による繰り返しマッチ
string match -ra '\d{10}' 'First number is 0123456789, second number is 1234567890'; echo $status
0123456789
1234567890
0
例)大文字小文字も無視したマッチ
string match -i 'app*' 'APPLE'; echo $status
APPLE
0
string match -ri '[aple]{5}' 'APPLE'; echo $status
APPLE
0
マッチした位置を返す
string match -rn '\d{10}' 'First number is 0123456789'; echo $status
17 10
0
マッチしなかったものを返す
string match -rv 'red|blue|pink' 'yellow'; echo $status
yellow
0
文字数の取得
length
サブコマンドは文字列の文字数を戻り値に返す。
string length [(-q | --quiet)] [STRING...]
文字列の文字数を取得
string length "abcdefg"
7
string length "色はにほへど散りぬるを"
11
文字数が0以上か検証
string length -q 'a'; echo $status
0
string length -q ''; echo $status
1