如何检查文件是否具有扩展名 .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
是以\n
ewline 分隔的 - 不可能遇到\n
ewline 作为^
一行中的第一个字符。您可以通过各种方式将\n
ewlines 放入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
,这样如果您想更改输出文件名,则无需编辑每一行。
请注意,我使用了-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
末尾的 意味着将打印这些行并且仅打印这些行。如果这不是您想要使用sed
命令执行的操作,请告诉我,我将根据需要进行编辑。