web-dev-qa-db-ja.com

Unixシェルで部分文字列を抽出する最も簡単な方法は?

Unixシェルで(正規表現を使用して)サブストリングを抽出する最も簡単な方法は何ですか?

簡単な意味:

  • 機能が少ない
  • オプションを減らす
  • 勉強を減らす

更新

正規表現自体が単純さと矛盾していることに気づき、最も単純なcutを選択した回答として選択しました。あいまいな質問でごめんなさい。このQAの現在の状態をより正確に表すために、タイトルを変更しました。

8
Eonil

cutは役に立つかもしれません:

$ echo hello | cut -c1,3
hl
$ echo hello | cut -c1-3
hel
$ echo hello | cut -c1-4
hell
$ echo hello | cut -c4-5
lo

シェルビルトインもこれに適しています。ここにサンプルスクリプトを示します。

#!/bin/bash
# Demonstrates shells built in ability to split stuff.  Saves on
# using sed and awk in Shell scripts. Can help performance.

shopt -o nounset
declare -rx       FILENAME=payroll_2007-06-12.txt

# Splits
declare -rx   NAME_PORTION=${FILENAME%.*}     # Left of .
declare -rx      EXTENSION=${FILENAME#*.}     # Right of .
declare -rx           NAME=${NAME_PORTION%_*} # Left of _
declare -rx           DATE=${NAME_PORTION#*_} # Right of _
declare -rx     YEAR_MONTH=${DATE%-*}         # Left of _
declare -rx           YEAR=${YEAR_MONTH%-*}   # Left of _
declare -rx          MONTH=${YEAR_MONTH#*-}   # Left of _
declare -rx            DAY=${DATE##*-}        # Left of _

clear

echo "  Variable: (${FILENAME})"
echo "  Filename: (${NAME_PORTION})"
echo " Extension: (${EXTENSION})"
echo "      Name: (${NAME})"
echo "      Date: (${DATE})"
echo "Year/Month: (${YEAR_MONTH})"
echo "      Year: (${YEAR})"
echo "     Month: (${MONTH})"
echo "       Day: (${DAY})"

それは出力します:

  Variable: (payroll_2007-06-12.txt)
  Filename: (payroll_2007-06-12)
 Extension: (txt)
      Name: (payroll)
      Date: (2007-06-12)
Year/Month: (2007-06)
      Year: (2007)
     Month: (06)
       Day: (12)

そして、上記のGnudifのように、状況が非常に困難になったときのために、常にsed/awk/Perlがあります。

12
davey

/usr/bin/expr

$ expr substr hello 2 3
ell

文字列の先頭に対してパターンを照合することもできます。

$ expr match hello h
1

$ expr match hello hell
4

$ expr match hello e
0

$ expr match hello 'h.*o'
5

$ expr match hello 'h.*l'
4

$ expr match hello 'h.*e'
2
3
mpb

Unixシェルには従来、正規表現サポートが組み込まれていません。 BashとZshはどちらも行うので、=~演算子を使用して文字列を正規表現と比較すると、次のようになります。

Bashの$BASH_REMATCH配列から部分文字列を取得できます。

Zshでは、BASH_REMATCHシェルオプションが設定されている場合、値は$BASH_REMATCH配列にあります。それ以外の場合は、$MATCH/$matchタイ変数ペアにあります(1つのスカラー、もう1つの配列)。 RE_MATCH_PCREオプションが設定されている場合は、PCREエンジンが使用されます。それ以外の場合は、システム正規表現ライブラリが、bashによる拡張正規表現構文の一致に使用されます。

だから、最も単純に:bashを使用している場合:

if [[ "$variable" =~ unquoted.*regex ]]; then
  matched_portion="${BASH_REMATCH[0]}"
  first_substring="${BASH_REMATCH[1]}"
fi

BashやZshを使用していない場合は、外部コマンドを使用する必要があるため、さらに複雑になります。

2
Phil P

テキストの構造に応じて、grepとsedがおそらく必要なツールです。

部分文字列が何であるかはわからないが、その周りにあるパターンはわかっている場合は、sedがうまくいくはずです。

たとえば、「#」記号で始まる数字の部分文字列を検索する場合は、次のように記述できます。

sed 's/^.*#\([0-9]\+\)/\1/g' yourfile

grepも同様の処理を実行できますが、問題は、部分文字列をどのように処理する必要があるか、および通常の行末区切りテキストを使用しているかどうかです。

2
Gnudiff