bash 如果不是没有子shell的多个条件?

Wil*_*ard 33 bash shell-script

我想在一个 shell if 语句中组合多个条件,并否定组合。对于条件的简单组合,我有以下工作代码:

if [ -f file1 ] && [ -f file2 ] && [ -f file3 ] ; then
  # do stuff with the files
fi
Run Code Online (Sandbox Code Playgroud)

这工作正常。如果我想否定它,我可以使用以下工作代码:

if ! ( [ -f file1 ] && [ -f file2 ] && [ -f file3 ] ) ; then
  echo "Error: You done goofed."
  exit 1
fi
# do stuff with the files
Run Code Online (Sandbox Code Playgroud)

这也按预期工作。但是,我突然想到我不知道括号实际上在做什么。我将它们仅用于分组,但它实际上是否产生了一个子外壳?(我怎么知道?)如果是这样,有没有办法在不产生子shell的情况下对条件进行分组?

cuo*_*glm 40

您需要使用{ list;}代替(list)

if ! { [ -f file1 ] && [ -f file2 ] && [ -f file3 ]; }; then
  : do something
fi
Run Code Online (Sandbox Code Playgroud)

它们都是Grouping Commands,但{ list;}在当前 shell 环境中执行命令。

请注意,需要;in{ list;}将列表与}反向词分隔,您也可以使用其他分隔符。后面的空格(或其他分隔符){也是必需的。

  • 您可以使用手册中的任何元字符引号`它们必须通过空格或另一个shell元字符与列表分开。`在bash中它们是:`元字符:| &; ( ) < > 空格制表符`。对于这个特定的任务,我相信任何`&; ) 空格选项卡` 将工作。.... .... 来自 zsh(作为注释):`每个子列表都以`;'、`&'、`&|'、`&!' 或换行符结尾。` (2认同)

zwo*_*wol 10

要在 shell 中可移植地否定复杂的条件,您必须要么应用德摩根定律并在[调用中一直向下推否定...

if [ ! -f file1 ] || [ ! -f file2 ] || [ ! -f file3 ]
then
    # do stuff
fi
Run Code Online (Sandbox Code Playgroud)

... 或者你必须使用then :; else...

if [ -f file1 ] && [ -f file2 ] && [ -f file3 ]
then :
else
  # do stuff
fi
Run Code Online (Sandbox Code Playgroud)

if ! command不可移植,也不可移植[[

如果您不需要完全的可移植性,请不要编写 shell 脚本。实际上,与您相比,您在随机选择的 Unix 上更有可能找到。/usr/bin/perlbash

  • `!` 是 POSIX,现在它已经足够便携了。即使仍然附带 Bourne shell 的系统在文件系统的其他位置也有 POSIX sh,您可以使用它来解释标准语法。 (3认同)

woo*_*god 9

您可以完全使用该test功能来实现您想要的。从手册页test

 ! expression  True if expression is false.
 expression1 -a expression2
               True if both expression1 and expression2 are true.
 expression1 -o expression2
               True if either expression1 or expression2 are true.
 (expression)  True if expression is true.
Run Code Online (Sandbox Code Playgroud)

所以你的情况可能看起来像:

if [ -f file1 -a -f file2 -a -f file3 ] ; then
    # do stuff with the files
fi
Run Code Online (Sandbox Code Playgroud)

为了否定使用转义括号:

if [ ! \( -f file1 -a -f file2 -a -f file3 \) ] ; then
    echo "Error: You done goofed."
    exit 1
fi
# do stuff with the files
Run Code Online (Sandbox Code Playgroud)

  • 请注意:根据[本文档](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html#tag_20_128_16),`-a`、`-o` 和 `(`/`) ` 已被标记为过时,应避免使用。 (2认同)

mik*_*erv 5

其他人已经注意到{复合命令;}分组,但如果您在一上执行相同的测试,您可能希望使用不同的类型:

if  ! for f in file1 file2 file3
      do  [ -f "$f" ] || ! break
      done
then  : do stuff
fi
Run Code Online (Sandbox Code Playgroud)

...正如在其他地方用 演示的那样{ :;},嵌套复合命令没有任何困难......

请注意,上述(通常)测试常规文件。如果你正在寻找只为现有的可读的文件,这是不是目录:

if  ! for f in file1 file2 file3
      do  [ ! -d "$f" ] && 
          [   -r "$f" ] || ! break
      done
then  : do stuff
fi
Run Code Online (Sandbox Code Playgroud)

如果您不在乎它们是否是目录:

if  ! command <file1 <file2 <file3
then  : do stuff
fi
Run Code Online (Sandbox Code Playgroud)

...适用于任何可读可访问的文件,但可能会挂起没有作者的 fifos。