なぜ

なぜ

「タイトル」で始まる名前のファイルがいくつかあります。 「.txt」で終わり、その間に他のコンテンツがある場合とない場合があります。たとえば:title.txt、、、title.abc.txttitle.123.txt

今、私はすべて別のフォルダにコピーしたいと思います。 1つのコマンドを使用してcpすべてのファイルをコピーする方法は?

正規表現を使用すると、次の操作を実行できます。

ls | egrep 'title(\..*)*\.txt' | xargs -I{} cp {} destination_folder/

しかし、あまりにも複雑です。egrepとの助けが必要ですxargs。シェルの組み込み関数glob/wildcardを使って魔法を実行する簡単な方法はありますか?それは次のとおりです。

cp title[magic]txt destination_folder/

答え1

標準シェルワイルドカードには対応するエントリはありませんが、一部のシェルにはいくつかの拡張機能があります。

扱いにくい

zshでは、これは#次のオプションで有効になる演算子ですextendedglob

set -o extendedglob # best in ~/.zshrc
cp -- *title(.*)#.txt* dest/

eglob修飾子を使用して、globでEREまたはPCREを使用できます。

cp -- *(e['[[ REPLY =~ "title(\..*)*\.txt" ]]']) dest/

set -o rematchpcreEREの代わりにPCREを使用するか、-pcre-match代わりに後で使用)=~zmodload zsh/pcre

ケシ

ksh(すべてのバージョン)では、x*次のようになります*(x)

cp -- *title*(.*).txt* dest/

強く打つ

bashは次のオプションでksh演算子をサポートしますextglob

shopt -s extglob
cp -- *title*(.*).txt* dest/

クッシュ 93

ksh93正規表現は対応するglobで使用できます。

cp -- *~(E:title(\..*)*\.txt)* dest/

(Eのため第二正規表現はここで拡張されます。)

また、次を使用してEREをグローバルモードに変換することもできます。

$ printf '%P\n' 'title(\..*)*\.txt'
*title*(\.*)\.txt*

(このバックスラッシュはここで冗長ですが)

答え2

基本ワイルドカードで特定の同じ正規表現を一致させる唯一の方法は次のとおりです。

cp title[.]txt title.*.txt destination_folder/

ファイルが存在すると仮定します(またはnullglobを設定すると、ファイルがまったくない場合はcpエラーが生成されます)。

または:

$ ksh -c '
      set -- ~(N)title[.]txt ~(N)title.*.txt
      [ $# -ge 1 ] && cp "$@" dir/
  '

または:

$ bash -O nullglob -c '
    set -- title[.]txt title.*.txt
    [ $# -ge 1 ] && cp "$@" dir/
  '

あるいは、他の殻にも似ています。


なぜ

*技術的には、globには正規表現と同じ項目がありません。

主に正規表現だけでは*意味がないからです。前に何かが来ると意味があり、これは前の表示(何か)0以上を繰り返すことを意味します。

まったく同等のものは次のとおりです。regexは.*globとまったく同じです*

正規表現に似た表現title(\..*)*\.txttitle.*.txt

始まりと終わり

grepに対して書く必要がある正確な正規表現は次のとおりです。

^title(\..*)*\.txt$

あなたの声明と一致「タイトル」から始めてください。そして「.txt」で終わる。正規表現では始まりは で表現し^、終​​わり度で表現しなければなりません。$

デフォルトでは、開始と終了はglobに含まれています。

指す

ドットは正規表現の特殊文字なので、エスケープする必要があります\.

ドットはグローバルに特別ではなく、エスケープする必要はありません。

オプションの文字

しかし、glob(デフォルト)ではオプションの文字を表現する方法はありません。

(c|d)?正規表現では、Aは「オプションのcまたはd」を意味しますcd 0番または1番、デフォルトのglobには対応するエントリはありません。これを行うには、以下を使用する必要があります。拡大するワイルドカード。オプションの文字列の構文は次のとおりです。

?(c|d)        # glob

だから:

?(.*)         # zero or once `?( )` a dot followed by anything (`*`).

意味:オプションで、ドットの後に何も(空の場合でも)一致します。

全体の大きな写真は次のとおりです。

title?(.*).txt            # only in extended globbing.

拡張ワイルドカードを設定する方法はシェルによって異なり、移植可能ではありません。

  • ksh : on by default, no need to set anything.
  • bash : shopt -s extglob
  • zsh : set -o extendedglob

ポータブル(ほぼ)

基本ワイルドカードで特定の同じ正規表現を一致させる唯一の方法は次のとおりです。

echo title[.]txt title.*.txt 

空のボール

しかし、上記のすべての試合は、いくつかの試合がグローバル展開の結果になると仮定しています。 globが一致するものを見つけられない場合(ファイルが見つからtitle[.]txtない場合title.txtなど)、nullglobシェルオプションを設定してglobを削除する必要があります(コマンドラインにそのままにするのではなく)。

しかし、これも移植性がありません。

  • ksh: nullglob オプションはありません。使用のみに適していますecho ~(N)title?(.*).txt
  • バッシュ: shopt -s nullglob
  • ジッシュ:set -o NULL_GLOBまたはset -G

また、nullglobが設定されていて一致するパターンがない場合、cpcpはこのコマンドラインを「確認」するため、エラーが生成されます。

cp  dir/

ソースは提供されません。

グローバル障害

FailGlobも同様の問題を引き起こす可能性があります。複数のパターンのいずれかが一致しない場合、コマンド全体が失敗します。

cp title[.]txt title?(.*).txt dir/

両方のモードのいずれかが失敗すると、両方のモードが失敗します。

決定的な

一致するものがまったくなく、cpでエラーが発生しなくてもcpを操作する唯一の方法は次のとおりです。

$ bash -O nullglob -c '
    set -- title[.]txt title.*.txt
    [ $# -ge 1 ] && cp "$@" dir/
  '

$ ksh -c '
      set -- ~(N)title[.]txt ~(N)title.*.txt
      [ $# -ge 1 ] && cp "$@" dir/
  '

関連情報