web-dev-qa-db-ja.com

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

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

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

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

joebloggsdomain.comを除いて、文字列のフォーマットは常に同じですので、cutを使用して文字列を2回分割できると思いますか

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

2番目の分割は/で分割し、最後のWord(joebloggs)を変数に格納します。

私は配列と分割を使ってphpでこれを行う方法を知っていますが、私はbashで少し迷っています。

87
Craig Edmonds

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

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
249
beroe

このように関数を定義します。

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

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

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

Sedについてはどうですか?それは単一のコマンドで動作します。

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

これが、正規表現と文字列を一致させる内訳です。

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

シングルsedを使用する

echo "/var/cpanel/users/joebloggs:DNS9=domain.com" | sed 's/.*\/\(.*\):.*/\1/'
10
Yann Moisan

単一のAwkを使う:

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

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

変数に格納するには

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

ユーザー名がフィールド5である必要がない、sedを使用したより柔軟な実装。

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

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

9
janos