如何在Bash中检查文件或文件目录是否存在?

19

我目前有一个bash脚本(位于我的主目录中,即/home/username/,我正在以root用户身份运行它,因为这对于复制图标是必要的):

cd /home/username/Pictures/Icon*

declare -a A={Arch,Debian,Fedora,Mageia,Manjaro,OpenSUSE}
declare -a B={Adwaita,Faenza,gnome,Humanity}

for i in $A; do
  for j in $B; do
    if test -e /usr/share/icons/$j/scalable ; else
        mkdir /usr/share/icons/$j/scalable/
    fi
    if test -e /usr/share/icons/$j/scalable/$i.svg ; else
      cp -a $i*.svg /usr/share/icons/$j/scalable/$i.svg
    fi
  done
done

我希望这个脚本要做的是将我的 Pictures/Icons and logos 目录中的图标复制到指定在$B 中的 /usr/share/icons 主题子目录中的 scalable。但在此之前,如果这些主题子目录中不存在scalable目录,我希望它可以创建它。然而,条件语句的else部分未被正确读取,因为我一直收到以下错误信息:
./copyicon.sh: line 8: syntax error near unexpected token `else'
./copyicon.sh: line 8: `    if test -e /usr/share/icons/$j/scalable ; else'

如果你想知道为什么条件语句中的 test -e ...,这是基于我一直在遵循的一本有关bash脚本的教材。

2个回答

24

检查文件和/或目录是否存在

要检查中是否存在文件,您可以使用-f运算符。对于目录,请使用-d。示例用法:

$ mkdir dir
$ [ -d dir ] && echo exists!
exists!
$ rmdir dir
$ [ -d dir ] && echo exists!
$ touch file
$ [ -f file ] || echo "doesn't exist..."
$ rm file
$ [ -f file ] || echo "doesn't exist..."
doesn't exist...

要获取更多信息,只需执行man test

-e是一个测试运算符,用于检查文件是否存在。虽然这似乎是一个不错的选择,但最好使用-f,如果文件不是常规文件,则返回false。例如,/dev/null是一个文件但不是常规文件。在这种情况下,检查返回true是不想要的。

关于变量的注意事项

确保也对变量进行引号处理,一旦变量中包含空格或任何其他特殊字符,它可能会产生不良副作用。因此,在测试文件和目录的存在性时,请用双引号括起文件/目录。像[ -f "/path/to/some/${dir}/" ]这样的语句将起作用,而以下语句如果dir中有空格,则会失败:[ -f /path/to/some/${dir}/ ]

修复语法错误

您在控制语句中遇到了语法错误。bash的if语句的结构如下:

if ...; then
    ...
fi

或者使用带有else子句的可选项:

if ...; then
    ...
else
    ...
fi

你不能省略 then 子句。如果你只想使用 else 子句,你应该否定条件。代码如下:
if [ ! -f "/usr/share/icons/$j/scalable" ]; then
    mkdir "/usr/share/icons/$j/scalable/"
fi

在这里,我们添加一个感叹号 (!) 来翻转表达式的评估。如果表达式评估为 true,那么同样的表达式前面加上 ! 将返回 false,反之亦然。

test -e ... 更改为 test [-d ...] 会导致以下错误:./copyicon.sh: 第8行:语法错误,附近有意外的标记 else' ./copyicon.sh: 第8行: if test [ -d /usr/share/icons/$j/scalable ] ; else' - Josh Pinto
那是因为你的语法有误。我会更新答案。 - ShellFish
“否定条件”是指感叹号(!)会在目录不存在时返回true,但在目录存在时返回false吗? - Josh Pinto
没错!感叹号可以将真变为假,反之亦然。- 因此,如果表达式为假,则带有 ! 的相同表达式将返回真,反之亦然! - ShellFish
我们如何检查/home/tmp目录中是否有*.txt文件? - Bhagesh Arora

9

你不能跳过if语句中的then部分,最简单的解决方案就是否定测试。

if [[ ! -e /usr/share/icons/${j}/scalable ]] ; then
    mkdir /usr/share/icons/${j}/scalable/
fi
if [[ ! -e /usr/share/icons/${j}/scalable/${i}.svg ]] ; then
  cp -a ${i}*.svg /usr/share/icons/${j}/scalable/${i}.svg
fi

我已经使用-e(存在)参数翻译,但你可以考虑对目录使用-d参数,对文件使用-f参数,并添加一些错误处理来捕获异常情况(例如/usr/share/icons/$j/scalable/存在,但出于某种原因它是一个文件而不是一个目录)。我还注意到在你的原始代码中,你可能会尝试将多个文件复制到一个文件中:
cp -a $i*.svg /usr/share/icons/$j/scalable/$i.svg

我在示例中保留了这种方式,以防您确定它始终只有一个文件并且正在进行有意的重命名。 如果不是,请仅指定目标目录。


这太棒了。对我来说,既适用于目录,也适用于文件。 :) - Devin Rhode
我们如何检查/home/tmp目录中是否有*.txt文件? - Bhagesh Arora

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接