文字列があります:
one_two_three_four_five
上記の文字列から変数A
value two
と変数B
value four
に保存する必要があります
フィールド区切り文字としてcut
を_
とともに使用して、必要なフィールドを取得します。
A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
B="$(cut -d'_' -f4 <<<'one_two_three_four_five')"
ヒア文字列の代わりにecho
とパイプを使用することもできます:
A="$(echo 'one_two_three_four_five' | cut -d'_' -f2)"
B="$(echo 'one_two_three_four_five' | cut -d'_' -f4)"
例:
$ s='one_two_three_four_five'
$ A="$(cut -d'_' -f2 <<<"$s")"
$ echo "$A"
two
$ B="$(cut -d'_' -f4 <<<"$s")"
$ echo "$B"
four
POSIX shコンストラクトのみを使用すると、 パラメーター置換コンストラクト を使用して、一度に1つの区切り文字を解析できます。このコードは、必要な数のフィールドがあることを前提としています。それ以外の場合は、最後のフィールドが繰り返されます。
string='one_two_three_four_five'
remainder="$string"
first="${remainder%%_*}"; remainder="${remainder#*_}"
second="${remainder%%_*}"; remainder="${remainder#*_}"
third="${remainder%%_*}"; remainder="${remainder#*_}"
fourth="${remainder%%_*}"; remainder="${remainder#*_}"
または、引用符で囲まれていないパラメーター置換を ワイルドカード展開 無効にして、 IFS
を区切り文字に設定 で使用できます(これは、区切り文字が単一の非-空白文字、または空白シーケンスが区切り文字の場合)。
string='one_two_three_four_five'
set -f; IFS='_'
set -- $string
second=$2; fourth=$4
set +f; unset IFS
これは、位置パラメータを破棄します。関数でこれを行うと、関数の位置パラメータのみが影響を受けます。
さらに別のアプローチは、read
ビルトインを使用することです。
IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF
awk
の解答を見たいと思ったので、ここに1つあります。
A=$(awk -F_ '{print $2}' <<< 'one_two_three_four_five')
B=$(awk -F_ '{print $4}' <<< 'one_two_three_four_five')
最も単純な方法(<<<のシェルの場合)は次のとおりです。
IFS='_' read -r a second a fourth a <<<"$string"
1つのシェルが不平を言うため、$a
の代わりに一時変数$_
を使用します。
完全なスクリプトでは:
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<<"$string"
echo "$second $fourth"
set -f
(パス名展開)の問題ではなく、IFSの変更はありません。位置パラメータ( "$ @")への変更はありません。
IFSやset -f
を変更せずにallシェル(そう、すべてのPOSIXが含まれています)に移植可能なソリューションの場合は、同等の(少し複雑な)ヒアドキュメントを使用します。
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<-_EOF_
$string
_EOF_
echo "$second $fourth"
この解決策(ヒアドキュメントと<<<
の使用の両方)が後続の改行をすべて削除することを理解してください。
そして、これは「ワンライナー」可変コンテンツに設計されています。
マルチライナーのソリューションは可能ですが、より複雑な構成が必要です。
Bashバージョン4.4では非常にシンプルなソリューションが可能です
readarray -d _ -t arr <<<"$string"
echo "array ${arr[1]} ${arr[3]}" # array numbers are zero based.
多くのPOSIXシェルには配列がないため、POSIXシェルに相当するものはありません。
配列を持つシェルの場合、次のように単純な場合があります。
(attsh、lksh、mksh、ksh、およびbashで動作することがテスト済み)
set -f; IFS=_; arr=($string)
ただし、変数とオプションを保持およびリセットするための追加の配管がたくさんあります。
string='one_* *_three_four_five'
case $- in
*f*) noglobset=true; ;;
*) noglobset=false;;
esac
oldIFS="$IFS"
set -f; IFS=_; arr=($string)
if $noglobset; then set -f; else set +f; fi
echo "two=${arr[1]} four=${arr[3]}"
Zshでは、配列は1から始まり、デフォルトでは文字列を分割しません。
これをzshで機能させるには、いくつかの変更を行う必要があります。
zsh
を使用すると、文字列を分割できます(_
)を配列に:
elements=(${(s:_:)string})
そして、配列インデックスを介して各/任意の要素にアクセスします:
print -r ${elements[4]}
zsh
では(ksh
/bash
とは異なり) 配列のインデックスは1から始まる であることに注意してください。
pythonソリューションは許可されますか?
# python -c "import sys; print sys.argv[1].split('_')[1]" one_two_three_four_five
two
# python -c "import sys; print sys.argv[1].split('_')[3]" one_two_three_four_five
four
別のawkの例;理解しやすい
A=\`echo one_two_three_four_five | awk -F_ '{print $1}'\`
B=\`echo one_two_three_four_five | awk -F_ '{print $2}'\`
C=\`echo one_two_three_four_five | awk -F_ '{print $3}'\`
... and so on...
変数でも使用できます。
仮定:
this_str = "one_two_three_four_five"
その後、次のように機能します:
A = `エコー$ {this_str} | awk -F_ '{print $ 1}' `
B = `エコー$ {this_str} | awk -F_ '{print $ 2}' `
C = `エコー$ {this_str} | awk -F_ '{print $ 3}' `
... 等々...