-eq:预期一元运算符

-eq:预期一元运算符
x=$?
if [ ${x} -eq '0' ]; then
echo "something missing"
exit 1
else
echo "all present"
fi

为什么我-eq: unary operator expected执行上面的时候会出现这样的情况?

我正在做的事情的更完整版本:

对于 `cat ${2}` 中的文件 #$2 是 file.txt
    如果 [ ! -f "${1}/${文件}"]; # $1 是一个路径
    然后
        echo "$文件丢失"
        诺托克=$?
完毕
如果 [ ${notok} -eq 0 ];
然后
    echo“需要检查”
    1号出口
别的
    echo“所有文件都存在”

答案1

看起来变量x未定义。

尝试一下

if [ ${x-1} -eq 0 ]

如果定义或未定义,则将${x-1}计算为$x的值。1

或者更好,我假设之前有一个命令x=$?,为什么不使用

if cmd arg1 ... argn
then
    # true
else
    # false
fi

答案2

好吧,现在你已经编辑了你的问题,我想我知道到底发生了什么。

假设我有一个目录 ( ~/dir),其中包含一些文件和一个文本文件 ( ~/file.txt),其中包含一些文件名:

$ ls ~/dir
1.txt  2.txt  3.txt  4.txt  5.txt
$ cat ~/file.txt
1.txt
2.txt
3.txt
4.txt
5.txt

据我所知,您的脚本读取 的内容~/file.txt并检查这些文件( 、 等)是否1.txt存在2.txt~/dir.

但是当脚本运行时:

$ script.sh ~/dir ~/file.txt
/home/user/bin/script.sh: line 11: [: -eq: unary operator expected
All files present

那么,发生了什么事?看一下这段代码摘录:

if [ ! -f "${1}/${file}" ]; # $1 is a path 
then 
    echo "$file is missing" 
    notok=$? 
fi

~/dir这里的主要缺陷是,如果和的内容~/file.txt匹配,则echo "$file is missing"; notok=$?永远不会被执行。然后,如果notok变量没有值,[ ${notok} -eq 0 ]则会失败,因为${notok}扩展为空(正如我们许多人所怀疑的那样)。

该缺陷不是唯一的缺陷,但它是您收到错误的原因[: -eq: unary operator expected

你如何解决它?

如果您不想重写脚本,只需初始化notok变量即可与任意数字不同0在你的主代码之前。例如:

notok='1'

for file in `cat ${2}` #$2 is file.txt 
do 
    if [ ! -f "${1}/${file}" ]; # $1 is a path 
    then 
        echo "$file is missing" 
        notok=$? 
    fi 
done 
if [ ${notok} -eq 0 ]; 
then 
    echo "need to check" 
    exit 1 
else 
    echo "All files present" 
fi

有用:

# When the content of ~/dir and ~/file.txt matches
$ ls ~/dir
1.txt  2.txt  3.txt  4.txt  5.txt
$ cat ~/file.txt
1.txt
2.txt
3.txt
4.txt
5.txt
$ script.sh ~/dir ~/file.txt
All files present

# When the content of ~/dir and ~/file.txt does not match
$ ls ~/dir
1.txt  2.txt  3.txt  4.txt  5.txt
$ cat ~/file.txt
foo
1.txt
2.txt
3.txt
4.txt
5.txt
$ script.sh ~/dir ~/file.txt
foo is missing
need to check

但如果我要重写脚本,我会这样做:

# Initialize variables
# It's possible to parse arguments like `-d DIR -f FILE` but let's keep simple
dir="${1}"
txt="${2}"
missing='0'

# Don't read lines with for!
while IFS='' read -r 'file'; do
  if [ ! -f "${dir}/${file}" ]; then
    echo "Missing file: ${file}"
    # Use a simple counter instead of catch the exit code of `echo`
    missing=$(( missing + 1 ))
  fi
done < "${txt}"

if [ "${missing}" -gt '0' ]; then
  echo "Total: ${missing}"
  exit '1'
else
  echo 'All files are present'
fi

答案3

我认为你真正想要的是rsync

rsync --list-only --files-from="$2" "$1" "$1/.."

最后一个参数是一个虚拟参数,但是是必要的;它可以是任何目录,只要它与其$1本身不是同一目录即可。

或者,如果您想要的只是退出状态和更少的冗长:

rsync --dry-run --files-from="$2" "$1" "$1/.."

2>/dev/null如果您愿意,可以选择在末尾添加真的只需要退出状态。)


现在,回顾一下您发布的损坏的脚本:

for file in `cat ${2}` #$2 is file.txt 

反引号已被弃用;看cmd*sh shell 中的反引号(即 )是否已被弃用?

您假设传入的文件名$2名称中没有任何空格或特殊字符;看为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?

你还假设列出的所有文件名称中$2没有任何特殊字符或空格。

并且您假设该列表足够短,不会超过 shell 参数列表的最大长度。如果列表包含通配符(例如/*/*/*/*/../../../../*/*/*/*),那么您将遇到很多很多问题。

do 
    if [ ! -f "${1}/${file}" ]; # $1 is a path 

你真的仅有的想要允许常规文件吗?不是任何类型的特殊文件,甚至不是目录?如果是这样,那么您可能需要修改rsync之前给出的命令。

另外,风格要点:! as[不太if ! [ -f "$1/$file" ]可能让你误入歧途。然而,在这个具体案例中,这并没有什么问题。 (如果你[ ! ... ]与缺少的双引号结合起来,你就是非常很可能会被引入歧途。)

    then 
        echo "$file is missing" 
        notok=$? 

除非命令失败,否则在任何情况下都echo将此处设置为 0。notok

当您意识到您已经检查了退出状态时,这甚至更愚蠢。您无需再次这样做。如果您在此处编写notok=1(并添加notok=0到脚本的顶部),您将获得更简单、更好的形式。

    fi 
done 
if [ ${notok} -eq 0 ]; 

缺少双引号字符。再次,参见为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?(并注意其副标题“稳健的文件名处理和 shell 脚本中其他字符串传递的介绍性指南”)。

then 
    echo "need to check" 

这个消息完全没有意义。需要检查什么吗?谁需要检查什么?啊?

    exit 1 
else 
    echo "All files present" 
fi

其余的都很好。是的。


替换脚本

if rsync --dry-run --files-from="$2" "$1" "$1/.." 2>/dev/null; then
  echo "All files present"
else
  echo "need to check"
  exit 1
fi

不允许列表中的目录的替换脚本(将对其引发错误)

if ! rsync --dry-run --files-from="$2" "$1" "$1/.." --no-dirs 2>&1 | grep -q .; then
  echo "All files present"
else
  echo "need to check"
  exit 1
fi

答案4

我非常喜欢冗长的脚本,但是

if [ X”$x” = X”0” ] ; then doThis ; else doThat ;fi

即使不完全正确,也是足够的。别跟我说话,我在 FreeBSD 库的一些脚本中看到了这一点。 OP 的真正问题是无法可靠地获取返回代码,但这似乎已被其他人修复。

相关内容