bash / cut / splitを使用して文字列の一部を抽出する


120

私はこのような文字列を持っています:

/var/cpanel/users/joebloggs:DNS9=domain.com

joebloggsこの文字列からユーザー名()を抽出して変数に格納する必要があります。

文字列の形式は、常にの例外と同じになりますjoebloggsdomain.com、私は、文字列を使用して二回に分割することができます考えていますので、cut

最初の分割は分割され:、最初の部分を変数に格納して、2番目の分割関数に渡します。

2番目の分割は/、最後の単語(joebloggs)を分割して変数に格納します

配列とスプリットを使用してphpでこれを行う方法を知っていますが、bashで少し迷っています。

回答:


331

joebloggs追加のプロセスなしでパラメーター展開を使用してbashでこの文字列から抽出するには...

MYVAR="/var/cpanel/users/joebloggs:DNS9=domain.com" 

NAME=${MYVAR%:*}  # retain the part before the colon
NAME=${NAME##*/}  # retain the part after the last slash
echo $NAME

joebloggsパスの特定の深さにいることに依存しません。


概要

参考のために、いくつかのパラメータ拡張モードの概要...

${MYVAR#pattern}     # delete shortest match of pattern from the beginning
${MYVAR##pattern}    # delete longest match of pattern from the beginning
${MYVAR%pattern}     # delete shortest match of pattern from the end
${MYVAR%%pattern}    # delete longest match of pattern from the end

つまり#、最初から一致することを意味し(コメント行を考える)%、最後から一致することを意味します。1つのインスタンスは最短を意味し、2つのインスタンスは最長を意味します。

数値を使用して、位置に基づいて部分文字列を取得できます。

${MYVAR:3}   # Remove the first three chars (leaving 4..end)
${MYVAR::3}  # Return the first three characters
${MYVAR:3:5} # The next five characters after removing the first 3 (chars 4-9)

以下を使用して、特定の文字列またはパターンを置き換えることもできます。

${MYVAR/search/replace}

patternファイル名のマッチングと同じフォーマットであるので、*(任意の文字)は共通であり、多くの場合のような特定のシンボルが続く/、または.

例:

のような変数を考える

MYVAR="users/joebloggs/domain.com" 

ファイル名を残すパスを削除します(スラッシュまでのすべての文字):

echo ${MYVAR##*/}
domain.com

パスを残して、ファイル名を削除します(最後のから最も短い一致を削除します/):

echo ${MYVAR%/*}
users/joebloggs

ファイル拡張子のみを取得します(最後の期間の前にすべて削除します):

echo ${MYVAR##*.}
com

注: 2つの操作を行うには、それらを組み合わせることはできませんが、中間変数に割り当てる必要があります。したがって、パスや拡張子なしでファイル名を取得するには:

NAME=${MYVAR##*/}      # remove part before last slash
echo ${NAME%.*}        # from the new var remove the part after the last period
domain

これがgrepのクリエイティブな使用に対する賛成か反対かはわかりませんが、VAR = / here / is / a / path:with / a / colon / inside:DNS9 = domain.com
rici

2
甘い!そしてそれは実行中のシェルの内部で行われるため、他のコマンドを使用するシェルよりもはるかに高速です。
stolsvik 2014年

3
@Fadiワイルドカードをコロンの前に置き、の#代わりに使用する必要があり%ます。あなたは非常に最後のコロンの後の部分のみを使用する場合は、使用が${MYVAR##*:}最初のコロン、使用後に一部を取得する${MYVAR#*:}
beroe

4
友よ、あなたが私がこの答えに何回戻ったのか分からない。ありがとうございました!
Joel B

1
正解です。質問:パターンが変数の場合、このように入力するのでしょう${RET##*$CHOP}か、それともこのように入力し${RET##*CHOP}ますか(または別の方法)?編集:前者のようです${RET##*$CHOP}
Ctrl S

42

次のような関数を定義します。

getUserName() {
    echo $1 | cut -d : -f 1 | xargs basename
}

そして、文字列をパラメータとして渡します:

userName=$(getUserName "/var/cpanel/users/joebloggs:DNS9=domain.com")
echo $userName

1
この答えは、私がここに来た目的を達成するのに役立ちました。受け入れられた答えはなく、これは単純さのために私の投票を得る。
harperville 14

1
上記のコマンドで私がしなければならなかった唯一の修正は、このように ':'を削除することecho $1 | cut -d -f 1 | xargsでした。シンプルで端正なansの+1。
ブーシャン2015年

20

セッドはどうですか?それは単一のコマンドで動作します:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • #代わりに、正規表現の仕切りに使用されている/文字列が有しているため/、それに。
  • .*/ 最後のバックスラッシュまで文字列を取得します。
  • \( .. \)キャプチャグループをマークします。これです\([^:]*\)
    • [^:]コロン_except任意の文字、と言う*意味ゼロ以上。
  • .* 残りの行を意味します。
  • \1最初の(そして唯一の)キャプチャグループで見つかったものを置き換えることを意味します。これが名前です。

文字列と正規表現を照合する内訳は次のとおりです。

        /var/cpanel/users/           joebloggs  :DNS9=domain.com joebloggs
sed 's#.*/                          \([^:]*\)   .*              #\1       #'

超いい解剖!
kyb


10

単一のawkを使用する:

... | awk -F '[/:]' '{print $5}'

つまり、フィールド区切り文字として/またはを使用すると:、ユーザー名は常にフィールド5にあります。

変数に格納するには:

username=$(... | awk -F '[/:]' '{print $5}')

これを使用したより柔軟な実装でsedは、ユーザー名をフィールド5にする必要はありません。

... | sed -e s/:.*// -e s?.*/??

つまり:、以降のすべてを削除し、最後まで削除します/sedはおそらくよりも速いawkので、この代替手段は間違いなく優れています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.