8

我正在尝试编写一个简单的脚本,它会告诉我 $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

但这不起作用。

4

7 回答 7

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*扩展为空。(没有它,它将保持原样。)
  • ( ... )设置一个子shell,防止shopt -s nullglob“逃逸”。
  • files=(/home/edward/bank1/fiche/Test*)将文件列表放入名为files. (请注意,这仅在子外壳中;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“逃避”。)

于 2013-03-09T00:24:06.377 回答
7

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

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

尝试这个:

 $ echo *

这将回显当前目录中的所有文件和目录。在echo命令执行之前,shell 会插入*并扩展它,然后将该扩展参数传递回您的命令。您可以通过执行以下操作来查看它的实际效果:

$ set -xv
$ echo *
$ set +xv

set -xv打开xtraceverbose。_ 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*

缺少引号(以及重要的介绍性斜线!)现在将使文件等于与该表达式匹配的所有文件。(可能不止一个!)。如果没有文件,取决于外壳程序及其设置,外壳程序可能只是将文件设置为该文字字符串。

你当然有正确的想法:

 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语句为并执行该if子句。如果命令返回非零值,if则假定语句为假,并执行else子句(如果有的话)。

test命令以类似的方式工作。如果test为真,则该test命令返回零。否则,该test命令返回一个非零值。这对if命令很有用。实际上,该命令有一个别名。test尝试这个:

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

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

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

if [ -s $file ]
then
    echo "The file exists"
fi
于 2013-07-23T03:02:47.210 回答
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 世界中),布尔值 true 是一个以状态 0 退出的程序。

ls尝试列出模式,如果成功(意味着模式存在),则以状态 0 退出,否则以 2 退出(有关详细信息,请查看 ls 手册页)。

在我们的例子中,实际上有 3 个表达式,为了清楚起见,我会加上括号,尽管它们不是必需的,因为&&优先于||

 (expression1 && expression2) || expression3

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

否则,如果 expression1 为 false,则不对 expression2 求值,但在本例中为 expression3。

于 2013-03-09T00:59:54.373 回答
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
于 2014-01-29T09:13:34.163 回答
0

如果该脚本存在于指定变量中,则以下脚本将帮助您进入进程,

cat > waitfor.csh

    #!/bin/csh

    while !( -e $1 )

    sleep 10m

    end

ctrl+D

-e是用于处理文件,

$1是一个外壳变量,

睡10分钟

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

于 2013-07-25T04:43:23.230 回答
0

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

awk 'BEGIN {print getline < "file.txt" < 0 ? "File does not exist" : "File Exists"}'
于 2016-10-06T10:49:35.787 回答
-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 ]
于 2013-03-09T00:23:19.203 回答