Bashで文字列を正規表現と一致させるにはどうすればよいですか?


166

私は与えられたときに機能が含まれているbashスクリプト記述しようとしています.tar.tar.bz2.tar.gzなどのファイルには、ファイルを解凍するために、関連するスイッチとタールを使用します。

私はif elif thenステートメントを使用して、ファイル名をテストしてそれが何で終わるかを確認し、正規表現のメタ文字を使用して一致させることができません。

コマンドラインで 'test'を使用しているスクリプトを常に書き換えるのを保存するために、以下のステートメントが機能するはずだと思いました。角括弧、引用符、メタ文字のすべての組み合わせを試しても、失敗します。

test sed-4.2.2.tar.bz2 = tar\.bz2$; echo $?
(this returns 1, false)

問題は単純なものであり、どこを見ても確認できましたが、どうすればよいかを理解することはできません。誰か私がこれを行う方法を知っていますか?

回答:


268

正規表現に一致させるには、=~演算子を使用する必要があります。

これを試して:

[[ sed-4.2.2.tar.bz2 =~ tar.bz2$ ]] && echo matched

または、次の==演算子で(正規表現の代わりに)ワイルドカードを使用できます。

[[ sed-4.2.2.tar.bz2 == *tar.bz2 ]] && echo matched

移植性が問題にならない場合は、より安全で強力な[[代わりに、[またはtestそれを使用することをお勧めします。参照してくださいテスト、[と[[の違いは何ですか?詳細については。


7
2番目の例では、globワイルドカードの一致に注意してください。[[]]内では、*は通常のように展開されず、パターンに一致する現在のディレクトリ内のファイル名に一致します。この例は機能しますが、過度に一般化して、誤って*が任意のコンテキスト。[[]]内ではそのようにのみ機能します。それ以外の場合は、既存のファイル名に展開されます。
アランポーター

7
正規表現で引用符を使用しようとしましたが失敗しました。この答えcheck="^a.*c$";if [[ "abc" =~ $check ]];then echo match;fi、正規表現を変数に保存する必要があるこの作業を行うのに役立ちました
Aquarius Power

また、(perlのような)正規表現は括弧で囲ま[[ sed-4.2.2.tar.bz2 == "*tar.bz2" ]]ないでください:機能しません。
pevik 2015

18
FWIW、否定の構文(つまり、一致しない)は[[ ! foo =~ bar ]]です。
Skippy le Grand Gourou 2017年

1
ダッシュは-n 1パラメータをサポートしていません$REPLY。また、自動的に変数に入れません。気を付けて!

54

これを行う関数

extract () {
  if [ -f $1 ] ; then
      case $1 in
          *.tar.bz2)   tar xvjf $1    ;;
          *.tar.gz)    tar xvzf $1    ;;
          *.bz2)       bunzip2 $1     ;;
          *.rar)       rar x $1       ;;
          *.gz)        gunzip $1      ;;
          *.tar)       tar xvf $1     ;;
          *.tbz2)      tar xvjf $1    ;;
          *.tgz)       tar xvzf $1    ;;
          *.zip)       unzip $1       ;;
          *.Z)         uncompress $1  ;;
          *.7z)        7z x $1        ;;
          *)           echo "don't know '$1'..." ;;
      esac
  else
      echo "'$1' is not a valid file!"
  fi
}

その他の注意

上記のコメントの水瓶座の力に応えて、 We need to store the regex on a var

変数BASH_REMATCHは、あなたが表現に一致した後に設定され、$ {BASH_REMATCH [n]は}以下に括弧すなわちに包まれたn番目のグループにマッチします${BASH_REMATCH[1]} = "compressed"し、${BASH_REMATCH[2]} = ".gz"

if [[ "compressed.gz" =~ ^(.*)(\.[a-z]{1,5})$ ]]; 
then 
  echo ${BASH_REMATCH[2]} ; 
else 
  echo "Not proper format"; 
fi

(上記の正規表現は、ファイルの名前と拡張子に対して有効なものではありませんが、例では機能します)


また、BSD tarを使用すると、すべての形式に「tar xf」を使用でき、個別のコマンドやこの関数をまったく必要としません。
良い人

aGNU tarまたはpBSD tarでは、拡張子から圧縮タイプを自動的に推測するよう明示的に指示します。それ以外の場合、GNU tarはそれを自動的に実行しません。@ GoodPersonのコメントから、BSD tarはデフォルトでそれを実行すると推測しています。
Mark K Cowan 2017

7zは.. AR、ARJ、CAB、CHM、CPIO、CramFS、DMG、EXT、FAT、GPT、HFS、IHEX、ISO、LZH、LZMA、MBR、MSI、NSIS、NTFS、QCOW2、RAR、RPM、SquashFSを解凍できます、UDF、UEFI、VDI、VHD、VMDK、WIM、XARとZ.参照7-zip.org
モッシュ

14

ここにコメントするのに十分な担当者がいないので、dogbaneの回答を改善するために新しい回答を提出します。ドット。正規表現で

[[ sed-4.2.2.tar.bz2 =~ tar.bz2$ ]] && echo matched

たとえば、「tar.bz2」の間のリテラルドットだけでなく、任意の文字に一致します。たとえば、

[[ sed-4.2.2.tar4bz2 =~ tar.bz2$ ]] && echo matched
[[ sed-4.2.2.tar§bz2 =~ tar.bz2$ ]] && echo matched

または「\」でエスケープする必要のないもの。厳密な構文は次のようになります

[[ sed-4.2.2.tar.bz2 =~ tar\.bz2$ ]] && echo matched

または、さらに厳密にして、前のドットを正規表現に含めることもできます。

[[ sed-4.2.2.tar.bz2 =~ \.tar\.bz2$ ]] && echo matched

9

bashを使用しているため、これを行うための子プロセスを作成する必要はありません。以下は、bash内で完全に実行する1つのソリューションです。

[[ $TEST =~ ^(.*):\ +(.*)$ ]] && TEST=${BASH_REMATCH[1]}:${BASH_REMATCH[2]}

説明:シーケンス「コロンと1つ以上のスペース」の前後のグループは、パターン一致演算子によってBASH_REMATCH配列に格納されます。


1
インデックス0には完全一致が含まれ、インデックス1および2にはグループ一致が含まれることに注意してください。
Rainer Schwarze

3
if [[ $STR == *pattern* ]]
then
    echo "It is the string!"
else
    echo "It's not him!"
fi

私のために働く! GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)


1
これは非常に危険です。現在のディレクトリにリテラル部分文字列「パターン」という名前のファイルがないため、未定義の動作なしでのみ動作します。さあ、そのような名前のファイルをいくつか作成してください。サブストリング展開はファイルと一致し、多色のheisenbugsですべてを恐ろしく壊します。
i336_

しかし、私は実験を行いました。現在のディレクトリにあるファイル `1pattern、pattern pattern2、およびpatternを使用します。このスクリプトは期待どおりに動作します。テスト結果を教えてください。@ i336_
juan

2
@ i336:そうは思いません。中で[[ ... ]]、RHSグロブパターンがないではないが、通常行うように、カレントディレクトリカントー応じて展開します。
user1934428

@ i336_いいえ。内では[[...]]、Bashはファイル名の拡張を実行しません。bashマニュアルでは、Word splitting and filename expansion are not performed on the words between the [[ and ]];
jinbeom hong

@jinbeomhong:TIL。知っておくと便利です。ありがとうございます。
i336_

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