用于检查文件是否存在的Shell脚本
我试图编写一个简单的脚本,告诉我$Temp中是否存在以字符串“Test”开头的文件名 例如,我有这些文件用于检查文件是否存在的Shell脚本,shell,Shell,我试图编写一个简单的脚本,告诉我$Temp中是否存在以字符串“Test”开头的文件名 例如,我有这些文件 Test1989.txt Test1990.txt Test1991.txt 然后我只想回显找到了一个文件 例如,类似这样的内容: file="home/edward/bank1/fiche/Test*" if test -s "$file" then echo "found one" else echo "found none" fi 但这不起作用。通配符不会在
Test1989.txt
Test1990.txt
Test1991.txt
然后我只想回显找到了一个文件
例如,类似这样的内容:
file="home/edward/bank1/fiche/Test*"
if test -s "$file"
then
echo "found one"
else
echo "found none"
fi
但这不起作用。通配符不会在带引号的字符串中展开。当扩展通配符时,如果没有匹配项,则返回原样,它不会扩展为空字符串。尝试:
output="$(ls home/edward/bank1/fiche/Test* 2>/dev/null)"
if [ -n "$output" ]
then echo "Found one"
else echo "Found none"
fi
如果通配符扩展为文件名,ls
将在stdout
上列出它们;否则,它将在stderr上打印错误,而在stdout上不打印任何内容。stdout
的内容分配给output
if[-n“$output”]
测试$output
是否包含任何内容
另一种写法是:
if [ $(ls home/edward/bank1/fiche/Test* 2>/dev/null | wc -l) -gt 0 ]
一种方法:
(
shopt -s nullglob
files=(/home/edward/bank1/fiche/Test*)
if [[ "${#files[@]}" -gt 0 ]] ; then
echo found one
else
echo found none
fi
)
说明:
将导致shopt-s nullglob
在没有与该模式匹配的文件的情况下展开为空。(没有它,它将完好无损。)/home/edward/bank1/fiche/Test*
设置子shell,防止(…)
进行“转义”shopt-s nullglob
将文件列表放入名为files=(/home/edward/bank1/fiche/Test*)
的数组中。(请注意,这仅在子shell中;files
文件在子shell退出后将无法访问。)
是此数组中的元素数“${#files[@]}”
编辑以解决后续问题(“如果我还需要检查这些文件中是否包含数据且不是零字节文件怎么办”): 对于这个版本,我们需要使用
-s
(正如您在问题中所做的那样),它还测试文件的存在性,因此不再使用shopt-s nullglob
了:如果没有文件与模式匹配,那么模式上的-s
将为false。因此,我们可以写:
(
found_nonempty=''
for file in /home/edward/bank1/fiche/Test* ; do
if [[ -s "$file" ]] ; then
found_nonempty=1
fi
done
if [[ "$found_nonempty" ]] ; then
echo found one
else
echo found none
fi
)
(此处,
(…)
用于防止文件和找到的文件
被“转义”。您可以在一行中执行此操作:
ls /home/edward/bank1/fiche/Test* >/dev/null 2>&1 && echo "found one" || echo "found none"
要理解它是什么,您必须分解命令并对布尔逻辑有基本的了解
直接从bash手册页:
[...]
expression1 && expression2
True if both expression1 and expression2 are true.
expression1 || expression2
True if either expression1 or expression2 is true.
[...]
在shell中(通常在unix世界中),布尔值true是一个状态为0的程序
ls
尝试列出模式,如果成功(意味着该模式存在),则退出状态为0,否则退出状态为2(有关详细信息,请查看ls手册页)
在我们的例子中,实际上有3个表达式,为了清楚起见,我将插入括号,尽管它们不是必需的,因为&&
优先于|
:
(expression1 && expression2) || expression3
因此,如果expression1为true(即:ls
找到模式),它将计算expression2(它只是一个回显,将以状态0退出)。在这种情况下,expression3永远不会被评估,因为|
左侧站点上的内容已经是真实的,尝试评估右侧的内容将是一种资源浪费
否则,如果expression1为false,则不计算expression2,但在本例中,expression3为。您必须了解Unix如何解释您的输入
标准unixshell在将参数传递给程序之前插入环境变量以及称为globs的变量。这与Windows有点不同,Windows让程序解释扩展
试试这个:
$ echo *
$ foo="this is the value of foo"
$ echo $foo
$ echo "$foo"
$ echo '$foo'
$ ls -li /bin/test /bin/[
这将回显当前目录中的所有文件和目录。在echo
命令执行之前,shell将插入*
并展开它,然后将展开的参数传递回您的命令。通过执行以下操作,您可以看到它正在运行:
$ set -xv
$ echo *
$ set +xv
set-xv
打开xtrace和verbose。Verbose回显输入的命令,xtrace回显将要执行的命令(即,在shell扩展之后)
现在试试这个:
$ echo "*"
请注意,将某些内容放在引号中会对shell隐藏glob表达式,并且shell无法展开它。试试这个:
$ foo="this is the value of foo"
$ echo $foo
$ echo "$foo"
$ echo '$foo'
$ ls -li /bin/test /bin/[
请注意,shell仍然可以在双引号内展开环境变量,但不能在单引号内展开
现在让我们看看你的陈述:
file="home/edward/bank1/fiche/Test*"
双引号阻止shell扩展glob表达式,因此file
等于literalhome/edward/bank1/finche/Test*
。因此,您需要执行以下操作:
file=/home/edward/bank1/fiche/Test*
缺少引号(以及重要的介绍性斜杠!)将使文件等于所有匹配该表达式的文件。(可能不止一个!)。如果没有文件,取决于shell及其设置,shell可能只是简单地将文件设置为该文本字符串
你肯定有正确的想法:
file=/home/edward/bank1/fiche/Test*
if test -s $file
then
echo "found one"
else
echo "found none"
fi
但是,如果有多个文件,您仍然可能会发现未返回任何文件。相反,您的test
命令可能会出错,因为参数太多
解决这一问题的一种方法可能是:
if ls /home/edward/bank1/finche/Test* > /dev/null 2>&1
then
echo "There is at least one match (maybe more)!"
else
echo "No files found"
fi
在本例中,我利用了ls
命令的退出代码。如果ls
找到一个可以访问的文件,则返回零退出代码。如果找不到匹配的文件,则返回非零退出代码。if
命令仅执行一个命令,然后如果该命令返回零,它将假定if
语句为true,并执行if
子句。如果命令返回非零值,则假定If
语句为false,并执行else
子句(如果有)
test
命令的工作方式类似。如果test
为真,则test
命令返回零。否则,test
命令将返回一个非零值。这对于if
命令非常有效。实际上,test
命令有一个别名。尝试
for entry in "/home/loc/etc/"/*
do
if [ -s /home/loc/etc/$entry ]
then
echo "$entry File is available"
else
echo "$entry File is not available"
fi
done
Hope it helps
awk 'BEGIN {print getline < "file.txt" < 0 ? "File does not exist" : "File Exists"}'