• 加筆
  • 2017.04.27
  • 修正
四 月
24
月曜日
2017

fish shellで文字列操作

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...]

単一置換

yellowblueへ置換。

string replace yellow blue 'red green yellow'

red green blue

全置換

全てのハイフンをアンダースコアへ置換。

string replace -a - _ RED-GREEN-BLUE

RED_GREEN_BLUE

大文字小文字を無視

大文字小文字を無視してyellowblueへ置換。

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