检查文件夹中是否存在某种类型的文件

检查文件夹中是否存在某种类型的文件

如何检查文件是否具有扩展名 .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 的 shell;该nullglob选项特定于 bash。您使用的大括号 ( {}) 适用于 C 样式 shell。

shopt -s nullglob设置该nullglob选项,它基本上告诉 Bash 未能匹配的 glob 应该扩展为空字符串。默认情况下,如果*.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

已经提供的解决方案是不必要地shell 特定的。您可以使用可移植语法实现相同的效果 - 从长远来看,这使得记住的内容更少,并且具有更健壮的额外优势,例如:

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和/或文件传输协议那样做不是以两个开始//

我认为其余的都是你单独操作的结果grep。您似乎正在尝试清除空白行,但是,正如我想象的那样,这些空白行首先只是由重复附加写入文件引起的。

因此,我们可以将for循环的输出直接写入输出文件,以便维护写入描述符直到~/Desktop/externalservers.txt循环完成,这应该避免写入任何空行。也许像:

for ... done >>outfile

或者

{ grouped ; command ; list ; } >>outfile

至少我可以告诉你,这句话可能达不到你想要的效果:

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

sed是以\newline 分隔的 - 不可能遇到\newline 作为^一行中的第一个字符。您可以通过各种方式将\newlines 放入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 shell 或较旧的 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

抑制-nsed 打印每一行的默认行为,将/[^[:space:]]/匹配与任何非空格字符匹配的任何行,并且p末尾的 意味着将打印这些行并且仅打印这些行。如果这不是您想要使用sed命令执行的操作,请告诉我,我将根据需要进行编辑。

相关内容