フォルダに特定の種類のファイルがあることを確認する

フォルダに特定の種類のファイルがあることを確認する

ファイル拡張子が.javaであることを確認する方法は?

これまで私は以下を持っています:

  for javaFile in *.java ; do
    {
        echo "The file $javaFile has : " >> ~/Desktop/externalServers.txt
        grep -E '^[^/]{2}.*http' $javaFile >> ~/Desktop/externalServers.txt     

        grep -E '^[^/]{2}.*ftp' $javaFile  >> ~/Desktop/externalServers.txt

        echo "----------------------------------------" >> ~/Desktop/externalServers.txt
        sed -e "s/[[:space:]]\+/ /g" ~/Desktop/externalServers.txt >> ~/Desktop/externalServersTemp.txt
        rm ~/Desktop/externalServers.txt
        mv ~/Desktop/externalServersTemp.txt ~/Desktop/externalServers.txt
        sed 's/^\n//' ~/Desktop/externalServers.txt >> ~/Desktop/externalServersTemp.txt
        rm ~/Desktop/externalServers.txt
        mv ~/Desktop/externalServersTemp.txt ~/Desktop/externalServers.txt

    } done

ただし、これを行うたびに、次のエラーが発生します。

grep: *.java: そのファイルやディレクトリはありません。

デフォルトでは、まずフォルダに.java型ファイルがあることを確認してから、スクリプトの実行を続行したいと思います。

答え1

Bashでは、次を使用します。

shopt -s nullglob
for pdfFile in *.java;do
    # your code goes here
done

この構文は Bourne のようなシェルで動作します。このnullglobオプションは bash にのみ適用されます。使用した中括弧()は{}Cスタイルシェル用です。

shopt -s nullglobこのnullglobオプションが設定されている場合、デフォルトでは一致しないglobを空の文字列に拡張する必要があることをBashに通知します。デフォルトでは、一致*.javaするものが見つからない場合はそれ自体が拡張されます(アスタリスクは保持されます)。

答え2

私が書いたスクリプトは次のとおりです。

set -- *.java
test -e "$1" && {
    fortyequals=$(printf '%040d\n' | tr 0 \=)
    for javaFile do
        printf '%s\nIn file: %s\n%s\n' \
            $fortyequals "$javaFile" $fortyequals
        grep -E '^[^/]{2}.*(ftp|http)' "$javaFile"       
    done 
} >>~/Desktop/externalservers.txt

すでに提供されているソリューションは次のとおりです。不必要にシェル固有。移植可能な構文を使用すると、同じ効果が得られます。これにより、長期的な記憶が少なく、より強力になるという追加の利点があります。例:

set -- *.java
test -e "$1" &&
    for javaFile do
#       ...iterate on $javaFile here...
    done

$javaFileもう一つの利点は、次のループの最新の値を維持するだけでなく、みんな$javaFile私たちがかつて持っていた価値$@。これにより、以下が可能になります。

...
done

echo "The previous for loop processed $# files."

echo "The first file processed was:"
printf "///\t'%s'\t///\n" "$1"

echo "The last file processed was:"
printf "///\t'%s'\t///\n" "$javaFile"

echo 'All files processed in the for loop were:'
printf "///\t'%s'\t///\n" "$@"

{巻き毛が大好きなら、巻き}毛にも使えます。bash (必ずしも必要ではありませんが)- しかし、両方の殻を分離する必要があります。予約語 }そしてdone好きです:

for ... do {
...
} ; done

私の提案は、ブロック全体をフェンスでブロックすることです。についてループforと実行するすべての後処理 - 空想的には、次のように異なります。&& 予約語良い:

set -- *.java
test -e "$1" && {
    for ... done
#   ...further processing on $@...
} 

振り返ってみると、正規表現でも大きな助けになることができたと思います...次の単語を含む行を探しているようです。httpそして/またはファイル転送プロトコルそういいえ2つで始まる//

残りは一人で行うことだと思いますgrep。空行を消そうとしているようですが、私が想像しているように、これらの空行は最初にファイルに繰り返し追加された結果にすぎません。

したがって、forループの出力を出力ファイルに直接書き込むことができるため、~/Desktop/externalservers.txtループが完了するまで書き込み記述子が保持されるため、空行を書く必要はありません。おそらく:

for ... done >>outfile

または

{ grouped ; command ; list ; } >>outfile

少なくともこの文章が望む効果を得ることができないかもしれないということはお話しできます。

sed 's/^\n//' $file

sedewline で区切られます。行の最初の文字でewlineに\n会うことはできません。さまざまな方法でパターン空間に目を引くことができますが、一部の処理なしでは絶対に入れることはできません。\n^\nsed

答え3

サンプルコードのもう一つの問題は一般的に望むものです。すべてのイテレータに二重引用符を使用してください。forループで使用するとき。

あなたのコード:

for javaFile in *.java ;
    {
        echo "The file $javaFile has : " >> ~/Desktop/externalServers.txt
        grep -E '^[^/]{2}.*http' $javaFile >> ~/Desktop/externalServers.txt     

        grep -E '^[^/]{2}.*ftp' $javaFile  >> ~/Desktop/externalServers.txt

しなければならない:

for javaFile in *.java ; do
        echo "The file $javaFile has : " >> ~/Desktop/externalServers.txt
        grep -E '^[^/]{2}.*http' "$javaFile" >> ~/Desktop/externalServers.txt

        grep -E '^[^/]{2}.*ftp' "$javaFile"  >> ~/Desktop/externalServers.txt

答え4

Josephのnullglob方法が最もエレガントですが、それを使用したくない場合や使用できない場合(例:bash以外のシェルまたは以前のbashバージョン)、これを行うこともできます(ファイル名に改行文字が含まれていないと仮定)。

file="~/Desktop/externalServers.txt"
while IFS= read -r javaFile
do
  echo "The file $javaFile has : " >> "$file"
  grep -E '^[^/]{2}.*http' "$javaFile" >> "$file"
  grep -E '^[^/]{2}.*ftp' "$javaFile"  >> "$file"

  echo "----------------------------------------" >> "$file"
  ## The -i flag enables in-place editing so you don't need
  ## to fiddle about with temp files.
  sed -i -e "s/[[:space:]]\+/ /g" "$file"
  sed -i -n '/[^[:space:]]/p' "$file"
done < <(find . -maxdepth 1 -name '*.java')

スペースを含むファイル名を適切に処理できるように、入力フィールド区切り文字を空白のままにしますIFS=。オプションは、バックスラッシュを特に処理しないことを-r示しますread(ファイル名にバックスラッシュを含めることができる場合)。この<(command)構造はプロセスの交換そして、あるコマンドの出力を別のコマンドの入力に渡す方法です。

$file出力ファイル名を変更したい場合は、すべての行を編集する必要がないようにこの変数を導入しました。

私は-isedフラグを使用しましたが、それを使用して元のファイルを編集でき、一時ファイルは必要ありません。また、これを行う理由はなく、rm foo.txt; mv bar.txt foo.txtいつでも実行できmv bar.txt foo.txt、ターゲットファイルを上書きします。今、このコマンドが何をすべきかわかりません。

sed 's/^\n//' ~/Desktop/externalServers.txt >> ~/Desktop/externalServersTemp.txt

空行を削除したかったのですが、うまくいかなかったので上から変更しました。

sed -i -n '/[^[:space:]]/p' ~/Desktop/externalServers.txt

-nすべての行を印刷するsedのデフォルトの動作を抑制します。/[^[:space:]]/これは、空白以外の文字に一致するすべての行と一致し、p最後に「s」はその行とその行のみを印刷することを意味します。これがコマンドでやりたいことではない場合は、お知らせください。sed必要に応じて編集します。

関連情報