web-dev-qa-db-ja.com

3番目の。(ドット)区切り文字で文字列を分割する方法

いくつかの調査を行いましたが、文字列を「。」で区切ることができます。しかし、置換したいのは3番目の「。」だけです。バージョン番号は実際には可変なので、どのように置換/分割できますか?

version: 1.8.0.110

しかし、私が欲しいのは次のような出力です:

version: 1.8.0-110
7
Tiger

使用されたsed例:

$ echo 'version: 1.8.0.110' | sed 's/\./-/3'
version: 1.8.0-110

説明:

sed s/search/replace/xは文字列を検索し、2番目を置き換えます。 xは置換するオカレンスを決定します-ここでは3番目です。多くの場合、gは、すべての出現を意味するxに使用されます。

ここでは、ドット.を置き換えたいと思いますが、これはsedsearch用語で期待する正規表現の特殊文字です。したがって、.\.にバックスラッシュして、リテラル.を指定します。

sed(ここでは円記号\)の引数に特殊文字を使用しているため、引数全体を単一引用符''で囲む必要があります。多くの人は、ここでは常に引用符を使用して、シェルに特別な文字(spaceなど)を使用するときに問題が発生しないようにしています。

32
Ned64

Bashを使用する

特にlastピリオドをダッシュ​​に置き換えたいように見えるので、これを行うのに外部プログラムは必要ありません。 Bashは文字列操作自体を処理できます。

あなたが持っていると思います

vers='version: 1.8.0.110'

答えは簡単です:

$ echo ${vers%.*}-${vers##*.}
1.8.0-110

%は、一致する右側の最も短い文字列を削除することを意味します。 ##は、一致する左側の最も長い文字列を削除することを意味します。

期間が4つ以上ある場合はどうなりますか?

上記で推定した最後の期間ではなく、実際に3番目の期間を置き換える場合は、bashで少しトリッキーになりますが、それでも可能です。たとえば、vers='version: 1.8.0.110.hut.hut.hut.hike!'、3番目のピリオド以降をすべて検索し、それを使用して文字列を切り捨てることができます。

$ end=${vers#*.*.*.}
$ start=${vers%$end}
$ echo ${start%.}-$end
version: 1.8.0-110.hut.hut.hut.hike!

別の方法:IFSを使用して文字列をbash配列に分割する

これは質問に対してはやり過ぎですが、文字列をコンポーネントに分割して配列にロードすると便利な場合があります。

IFS=. read -a foo <<<'version: 1.8.0.110.hut.hut.hut.hike!'

配列$foo何をいつ印刷するかを選択します。例えば、

echo -n $foo
for ((i=1; i<${foo[@]}; i++)); do 
  [[ i -eq 3 ]] && echo -n - || echo -n .
  echo -n ${foo[i]};
done
echo
3
hackerb9

この場合、3番目は最後の1つでもあります。常に最後の_._を変更する必要があると安全に想定できる場合は、次のようにすることができます。

_$ echo 'version: 1.8.0.110' | sed 's/\.\([^.]*\)$/-\1/'
version: 1.8.0-110
_

または、sedが_-E_をサポートしている場合(ほとんどの場合)は次のとおりです。

_$ echo 'version: 1.8.0.110' | sed -E 's/\.([^.]*)$/-\1/'
version: 1.8.0-110
_

これは、_._を検索し、その後、行の終わり(_._)まで0以上の非_[^.]_文字(_$_)を検索します。 _[^.]*_は括弧(\( \))内にあるため、「キャプチャー」され、置換演算子の右側で_\1_として参照できます。したがって、これは_._およびその後ろのnon _-._文字を_-_およびそれらの文字に置き換えます。


最後ではなく3番目にする必要がある場合、 @ Ned64はすでに最も単純なアプローチを提供しています ですが、代わりに次のようにすることもできます。

_$ echo 'version: 1.8.0.110' | Perl -pe 's/(([^.]+\.){2}[^.]+)\./$1-/'
version: 1.8.0-110
_
2
terdon