用于检查文件是否存在的Shell脚本

时间:2013-03-09 00:13:17

标签: 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

但这不起作用。

7 个答案:

答案 0 :(得分:8)

一种方法:

(
  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*扩展为 nothing 。 (没有它,它将保持不变。)
  • ( ... )设置子shell,阻止shopt -s nullglob“转义”。
  • files=(/home/edward/bank1/fiche/Test*)将文件列表放在名为files的数组中。 (请注意,这仅在子shell中;在子shell退出后将无法访问files。)
  • "${#files[@]}"是此数组中元素的数量。

编辑以解决后续问题(“如果我还需要检查这些文件中是否包含数据并且不是零字节文件,那该怎么办”):

对于这个版本,我们需要使用-s(正如你在你的问题中所做的那样),它也测试文件的存在,所以再也没有使用shopt -s nullglob:如果没有文件匹配模式,然后模式上的-s将是假的。所以,我们可以写:

(
  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
)

(此处( ... )旨在阻止filefound_file“转义”。)

答案 1 :(得分:5)

您必须了解Unix 如何解释您的输入。

标准Unix shell在将参数传递给程序之前插入环境变量以及所谓的 globs 。这与Windows有点不同,它使程序解释扩展。

试试这个:

 $ echo *

这将回显当前目录中的所有文件和目录。在echo命令行动之前,shell会插入*并展开它,然后将该扩展参数传递回您的命令。你可以通过这样做看到它:

$ set -xv
$ echo *
$ set +xv

set -xv打开 xtrace 详细。 Verbose回显输入的命令, xtrace 回显将要执行的命令(即shell扩展后)。

现在试试这个:

$ echo "*"

请注意,在引号内放置一些内容会隐藏shell中的 glob表达式,并且shell无法展开它。试试这个:

$ foo="this is the value of foo"
$ echo $foo
$ echo "$foo"
$ echo '$foo'

请注意,shell仍然可以在双引号内扩展环境变量,但不能在单引号中扩展。

现在让我们来看看你的陈述:

file="home/edward/bank1/fiche/Test*"

双引号阻止shell扩展 glob表达式,因此file等于文字home/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

但是,如果有多个文件,您仍然可能会返回 found none 。相反,您可能会在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命令有一个别名。试试这个:

 $ ls -li /bin/test /bin/[

i打印出 inode inode 是文件的真实ID。具有相同ID的文件是相同的文件。您可以看到/bin/test/bin/[是相同的命令。这使得以下两个命令相同:

if test -s $file
then
    echo "The file exists"
fi

if [ -s $file ]
then
    echo "The file exists"
fi

答案 2 :(得分:3)

您可以在一行中完成:

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世界中),boolean true是一个退出状态为0的程序。

ls尝试列出模式,如果成功(意味着模式存在),则退出状态为0,否则为2(详情请参阅ls手册页)。

在我们的例子中,实际上有3个表达式,为了清楚起见,我将放括号,但不需要它们,因为&&优先于||

 (expression1 && expression2) || expression3

所以如果expression1为真(即:ls找到了模式),它会计算表达式2(这只是一个回声并将以状态0退出)。在这种情况下,表达式3永远不会被评估,因为||的左侧站点上的内容已经是真的,并且在尝试评估右侧的内容时会浪费资源。

否则,如果expression1为false,则不计算expression2,但在这种情况下,expression3为。

答案 3 :(得分:1)

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

答案 4 :(得分:0)

如果该脚本存在于指定的变量

中,以下脚本将帮助您转到进程
cat > waitfor.csh

    #!/bin/csh

    while !( -e $1 )

    sleep 10m

    end

ctrl+D

此处-e用于处理文件,

$1是一个shell变量,

睡10分钟

你可以通过./waitfor.csh ./temp ; echo "the file exits"

执行脚本

答案 5 :(得分:0)

是否存在一个检查文件的衬垫 -

awk 'BEGIN {print getline < "file.txt" < 0 ? "File does not exist" : "File Exists"}'

答案 6 :(得分:-1)

通配符不会在引用的字符串中展开。当扩展通配符时,如果没有匹配则返回不变,它不会扩展为空字符串。尝试:

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 ]