お知らせがあります。あなたはBashスクリプトを書いています、あなたはプログラマーです!
正規表現(RE)は「間違った」タイプです。バニラgrep
は「基本正規表現」(BRE)と呼ばれる形式を使用しますが、REは拡張正規表現(ERE)の形式です。BREは、バニラ、、、grep
などで使用されます。EREは、他のほぼすべての、、、、、などで使用されます。問題は、ファイル名ではなく、ファイルの内容でそのパターンを検索しようとしていることです。vi
more
awk
Perl
Python
Java
.Net
コマンドがありegrep
ます、またはあなたが使うことができるgrep -E
ので:
echo $zip|grep -E '^[0-9]\.[0-9]{1,2}\.[0-9]{1,2}$'
(一重引用符は二重引用符よりも安全であることに注意してください)。ちなみに、^
先頭と$
末尾で使用します。つまり、ファイル名はバージョン番号のみで構成されますが、バージョン番号は「ファイル名のどこかにある」と言います。数量詞は必要ありません{1}
、それは暗示されています。
ただし、バージョン番号も取得していないようです。
あなたは使用することができますsed
(私たちも必要です-E
):
ver=$(echo $zip| sed -E 's/.*([0-9]\.[0-9]{1,2}\.[0-9]{1,2}).*/\1/')
右側は、\1
「すべてを(前と後ろに。*があるので)括弧グループで一致したものに置き換える」ことを意味します。それは少し不格好です、私は知っています。
これで、次のことができるようになりますmkdir
(すべてを1行にまとめるメリットはなく、コードの保守が難しくなります)。
mkdir -p "$MODS/out/$ver"
${ver}
この場合は不要ですが、コンポーネントのいずれかに空白が埋め込まれている場合に備えて、パス名を二重引用符で囲むことをお勧めします。
したがって、特にそのREを生成する際には、「非プログラマー」のために十分な努力を払ってください。
さて、レッスン2です
一般的なループでこのソリューションを使用する場合は注意が必要です。あなたの質問は特にを使用しselect
ているため、どのファイルが使用されるかを予測することはできません。しかし、すべてのファイルに対してこれを実行したい場合はどうでしょうか。
上記のソリューションをfor
またはwhile
ループで使用すると、非効率になります。ループ内で外部プロセスを呼び出すことは常に悪いことです。mkdir
PerlやPythonのような別の言語を使用せずに私たちができることは何もありません。ただしsed
、その性質上、反復的であるため、その機能を使用する必要があります。
1つの代替方法は、の代わりにシェルパターンマッチングsed
を使用することです。この特定のパターンはシェルでは不可能ではありませんが、それは困難であり、他の疑問を提起します。だから、に固執しましょうsed
。
私たちが抱えている問題は、echo
出力が各フィールドの間にスペースを置くことです。それは私たちにいくつかの問題を与えます。 sed
各レコードを改行「\n」で区切るため、ここecho
ではそれ自体では機能しません。各スペースを改行で置き換えることはできますが、ファイル名内にスペースがある場合は問題になります。グロブを使っていくつかのトリックを行うことはできますIFS
が、それは不必要な複雑化につながります。したがって、代わりに古き良きにフォールバックしls
ます。通常は使用したくないのでls
、シェルグロブの方が効率的ですが、ここでは、各ファイル名の後に改行を配置する機能を使用しています(パイプを介してリダイレクトして使用する場合)。
while read ver
do
mkdir "$ver"
done < <(ls $SRC/*.zip|sed -E 's/.*([0-9]{1}\.[0-9]{1,2}\.[0-9]{1,2}).*/\1/')
ここではプロセス置換ls
を使用していますが、このループは1回だけ呼び出しますsed
。しかし、それはmkdir
プログラムをn回呼び出します。
レッスン3
申し訳ありませんが、それでも非効率的です。反復ごとに子プロセスを作成しています。ディレクトリを作成するには、カーネルAPI呼び出しが1つだけ必要ですが、そのためのプロセスを作成していますか?Perlのようなより洗練された言語を使用しましょう:
#!/usr/bin/perl
use warnings;
use strict;
my $SRC = '.';
for my $file (glob("$SRC/*.zip"))
{
$file =~ s/.*([0-9]{1}\.[0-9]{1,2}\.[0-9]{1,2}).*/$1/;
mkdir $file or die "Unable to create $file; $!";
}
あなたのREがここまで到達したことに注意してください!しかし、今ではより多くの制御が可能になり、子プロセスはありません(mkdir
Perlには組み込みのプロセスがありますglob
)。
結論として、ファイルの数が少ない場合は、sed
上記のループで問題ありません。シンプルでシェルベースです。これだけのためにスクリプトからPerlを呼び出すと、perlが非常に大きいため、おそらく遅くなります。ただし、ループ内に子プロセスを作成するシェルスクリプトはスケーラブルではありません。Perlはです。