我使用以下代码,它是这个脚本我用它来更新我的 WordPress 网站:
#!/bin/bash
drt="/var/www/html"
for dir in ${drt}/*/; do
if pushd "$dir"; then
wp plugin update --all --allow-root
wp core update --allow-root
wp language core update --allow-root
wp theme update --all --allow-root
popd
fi
done
当我寻找一种一次性更新所有 WordPress 实例的方法时,我了解了此代码中使用的特定pushd
模式。popd
我不清楚为什么这段代码包含一个if-fi
段。
我的问题
我可以以某种方式更改语法,以便我拥有基本相同的模式但没有if-fi
段吗?
例如,改为:
if pushd "$dir";
popd
commands
fi
我会有这样的伪代码:
pushd "$dir";
commands
popd
为什么我问这个
我可以想象我们如何在没有声明if-fi
(伪代码)的情况下告诉计算机这样的事情:
for dir in ${drt}/*; do pushd "$drt"; then
commands
popd
笔记
您可能希望在答案中包含不同的方法(即根本不包含)
pushd
。popd
答案1
此外@Olorin 写的我认为这里可能存在一些误解。首先,for y in ${x}/*; do pushd "$y"; then
结果为
bash:意外标记“then”附近的语法错误
第二,缩进可能会误导您关于实际发生的事情。采用原始代码的正确格式版本:
for y in ${x}/*/
do
if pushd "$y"
then
command1
command2
popd
fi
done
换句话说,所有的 command1
,command2
并且popd
仅在初始pushd
成功时才运行。如果你改为写
for y in ${x}/*/
do
pushd "$y"
command1
command2
popd
done
而且没有errexit
警卫到位,失败pushd
或popd
不会影响剧本的其余部分。这可能会导致运行command1
并command2
进入错误的目录,然后可能会弹回另一个目录与此代码无关。这可能会带来灾难性的后果。
最后我想说的是pushd
+ 命令 +popd
是反模式因为它为语言增加了更多的上下文(因此认知开销和风险),而复杂的上下文已经是一个大问题。解决此问题的最常见方法是将路径(最好是绝对路径)传递给命令,如下所示:
for y in "$x"/*/
do
command1 "$y"
command2 "$y"
done
答案2
如果pushd
失败会发生什么?如果要在这些目录中运行命令,显然应该pushd
在继续执行命令之前检查是否成功。
答案3
使用 if 是防止更改目录失败的合理保护措施。
如果该目录不可执行(无 x 权限),此代码将执行父目录中的命令。
#!/bin/bash
drt="/var/www/html"
for dir in "${drt}"/*/
do pushd "$dir"
pwd
popd
done
构建几个目录,更改所有者和权限:
$ mkdir -p /var/www/html/{one,two}
$ sudo chown user:user /var/www/html/{one,two}
$ sudo chmod o-x /var/www/html/two
$ ./script
/var/www/html/one ~/temp
/var/www/html/one
~/temp
./script: line 5: pushd: ./var/www/html/two/: Permission denied
~/temp
./script: line 7: popd: directory stack empty
命令 Pushd 发出错误,但命令 pwd 是在 ~/temp 目录中执行的(请注意错误后打印的 ~/temp 的值)。这显然是做错事的风险。与此脚本比较:
#!/bin/bash
drt="./var/www/html"
for dir in "${drt}"/*/
do if pushd "$dir" 2>/dev/null
then
pwd
popd
fi
done
执行的新脚本:
$ ./script
/var/www/html/one ~/temp
/var/www/html/one
~/temp
或者甚至更好:
#!/bin/bash
drt="./var/www/html"
for dir in "${drt}"/*/
do if pushd "$dir" 2>/dev/null
then
pwd
popd
else
echo "Failed to change to dir=$dir" >&2
exit 7
fi
done
在执行时,将打印:
$ ./script
/var/www/html/one ~/temp
/var/www/html/one
~/temp
Failed to change to dir=/var/www/html/two/
答案4
使用 gnu-find,您可以:
find ${drt} -maxdepth 1 -type d -execdir command1 ";" -execdir command2 ";"
请注意,并非每个 find 实现都有 -execdir 选项。