ファイル拡張子が.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
sed
ewline で区切られます。行の最初の文字でewlineに\n
会うことはできません。さまざまな方法でパターン空間に目を引くことができますが、一部の処理なしでは絶対に入れることはできません。\n
^
\n
sed
答え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
出力ファイル名を変更したい場合は、すべての行を編集する必要がないようにこの変数を導入しました。
私は-i
sedフラグを使用しましたが、それを使用して元のファイルを編集でき、一時ファイルは必要ありません。また、これを行う理由はなく、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
必要に応じて編集します。