在使用 for 循环遍历目录时遇到问题
Having trouble with for loop to iterate over a directory
我正在尝试 运行 我在 android 上的 magisk 模块中的这部分代码,因此它使用 android mksh shell。
我的目标是跳过 $MODULESPATH 中的 Fontchanger 文件夹,因为 Fontchanger 是我的模块,如果该文件夹不是 fontchanger 并且它没有名为 disable 的文件并且它有一个 system/fonts 目录$i,才应该代码运行。但是,当我去安装我的 magisk 模块 zip 时,运行 这段代码检测 $MODULESPATH 中的 Fontchanger 并中止。这与我需要的相反。它需要跳过 Fontchanger 文件夹。
这是代码
imageless_magisk && MODULESPATH=/data/adb/modules || MODULESPATH=/sbin/.core/img
for i in $MODULESPATH/*; do
if [ $i != Fontchanger ]; then
if [ ! -f $i/disable ]; then
if [ -d $i/system/fonts ]; then
NAME=$(get_var $i/module.prop)
ui_print " [!] "
ui_print " [!] Module editing fonts detected [!] "
ui_print " [!] Module - $NAME [!] "
ui_print " [!] "
abort
fi
fi
fi
done
imageless_magisk && MODULESPATH=/data/adb/modules_update || MODULESPATH=/sbin/.core/img
for i in $MODULESPATH/*; do
if [ $i != Fontchanger ]; then
if [ ! -f $i/disable ]; then
if [ -d $i/system/fonts ]; then
NAME=$(get_var $i/module.prop)
ui_print " [!] "
ui_print " [!] Module editing fonts detected [!] "
ui_print " [!] Module - $NAME [!] "
ui_print " [!] "
abort
fi
fi
fi
done
get_var() { sed -n 's/^name=//p' ; }
imageless_magisk() {
[ $MAGISK_VER_CODE -gt 18100 ]
return $?
}
在此先感谢您提供的所有帮助
mksh
上游开发者在这里 ☻
我通常建议人们反对 set -e
和 ,尤其是 set -u
,因为它们会在复杂的控制结构中引入不明显的故障。但是,我目前没有看到任何使用未使用变量的东西。另一方面,上游手册页最新版本(尚未发布)的 CAVEATS 部分描述了 set -e
和 set -o pipefail
之间的交互,最近才被追踪到:
Using set -o pipefail makes the following construct error out:
set -e
for x in 1 2; do
false && echo $x
done | cat
This is because, while the “&&” ensures that the inner command's failure
is not taken, it sets the entire for..done loop's errorlevel, which is
passed on by -o pipefail. Invert the inner command: true || echo $x
这可能影响嵌套的if
s,但我不确定这里。
另一方面,这部分代码肯定检查错了:
if [ $i != Fontchanger ]; then
记住,上面那行是……
for i in $MODULESPATH/*; do
... 所以 $i
会类似于 $MODULESPATH/Fontchanger
。另外,在 ! imageless_magisk
的情况下,你 运行 超过 /sbin/.core/img
两次。
请允许我提出一个希望等效的重构代码(与嵌套 if
相比,我更喜欢失败优先的方法,并且 ||
条件比 set -e
更稳定, 和 [[
条件使用起来更安全):
if imageless_magisk; then
set -A MODULESPATHS -- /data/adb/modules /data/adb/modules_update
else
set -A MODULESPATHS -- /sbin/.core/img
fi
for MODULESPATH in "${MODULESPATHS[@]}"; do
for i in "$MODULESPATH"/*; do
[[ $i = */Fontchanger ]] || continue
[[ ! -f $i/disable ]] || continue
[[ -d $i/system/fonts ]] || continue
NAME=$(get_var "$i"/module.prop)
ui_print " [!] "
ui_print " [!] Module editing fonts detected [!] "
ui_print " [!] Module - $NAME [!] "
ui_print " [!] "
abort
done
done
你甚至可以这样做:只在最后失败,列出 所有 具有“模块编辑字体”的目录,而不是在第一次出现后失败:
if imageless_magisk; then
set -A MODULESPATHS -- /data/adb/modules /data/adb/modules_update
else
set -A MODULESPATHS -- /sbin/.core/img
fi
do_abort=0
for MODULESPATH in "${MODULESPATHS[@]}"; do
for i in "$MODULESPATH"/*; do
[[ $i = */Fontchanger ]] || continue
[[ ! -f $i/disable ]] || continue
[[ -d $i/system/fonts ]] || continue
NAME=$(get_var "$i"/module.prop)
if (( !do_abort )); then
ui_print " [!] "
ui_print " [!] Module editing fonts detected [!] "
do_abort=1
fi
ui_print " [!] Module - $NAME [!] "
done
done
if (( do_abort )); then
ui_print " [!] "
abort
fi
这些代码 应该 是 set -u
和 set -eo pipefail
安全的。如果不是,我需要一个日志(在某处添加 set -x
)来查看它在哪里中断,因为我手边没有 Magisk 环境。 shell 版本 (echo $KSH_VERSION
) 也会派上用场;大多数 Android 附带非常旧的 mksh
版本。
希望这对您有所帮助;如果没有,请随时 ping 我,我会修改我的答案。
MODULESPATH=/data/adb/modules
imageless_magisk || MODULESPATH=/sbin/.core/img
for i in $MODULESPATH*/*; do
if [[ $i != *Fontchanger ]] && [ ! -f $i/disable ] && [ -d $i/system/fonts ]; then
NAME=$(get_var $i/module.prop)
ui_print " [!] "
ui_print " [!] Module editing fonts detected [!] "
ui_print " [!] Module - $NAME [!] "
ui_print " [!] "
cancel
fi
done
这是我们想出的代码,它可以工作并且已设置 - euxo pipefail 也兼容并且可以在 magisk 环境 Android 上工作
我正在尝试 运行 我在 android 上的 magisk 模块中的这部分代码,因此它使用 android mksh shell。
我的目标是跳过 $MODULESPATH 中的 Fontchanger 文件夹,因为 Fontchanger 是我的模块,如果该文件夹不是 fontchanger 并且它没有名为 disable 的文件并且它有一个 system/fonts 目录$i,才应该代码运行。但是,当我去安装我的 magisk 模块 zip 时,运行 这段代码检测 $MODULESPATH 中的 Fontchanger 并中止。这与我需要的相反。它需要跳过 Fontchanger 文件夹。
这是代码
imageless_magisk && MODULESPATH=/data/adb/modules || MODULESPATH=/sbin/.core/img
for i in $MODULESPATH/*; do
if [ $i != Fontchanger ]; then
if [ ! -f $i/disable ]; then
if [ -d $i/system/fonts ]; then
NAME=$(get_var $i/module.prop)
ui_print " [!] "
ui_print " [!] Module editing fonts detected [!] "
ui_print " [!] Module - $NAME [!] "
ui_print " [!] "
abort
fi
fi
fi
done
imageless_magisk && MODULESPATH=/data/adb/modules_update || MODULESPATH=/sbin/.core/img
for i in $MODULESPATH/*; do
if [ $i != Fontchanger ]; then
if [ ! -f $i/disable ]; then
if [ -d $i/system/fonts ]; then
NAME=$(get_var $i/module.prop)
ui_print " [!] "
ui_print " [!] Module editing fonts detected [!] "
ui_print " [!] Module - $NAME [!] "
ui_print " [!] "
abort
fi
fi
fi
done
get_var() { sed -n 's/^name=//p' ; }
imageless_magisk() {
[ $MAGISK_VER_CODE -gt 18100 ]
return $?
}
在此先感谢您提供的所有帮助
mksh
上游开发者在这里 ☻
我通常建议人们反对 set -e
和 ,尤其是 set -u
,因为它们会在复杂的控制结构中引入不明显的故障。但是,我目前没有看到任何使用未使用变量的东西。另一方面,上游手册页最新版本(尚未发布)的 CAVEATS 部分描述了 set -e
和 set -o pipefail
之间的交互,最近才被追踪到:
Using set -o pipefail makes the following construct error out:
set -e
for x in 1 2; do
false && echo $x
done | cat
This is because, while the “&&” ensures that the inner command's failure
is not taken, it sets the entire for..done loop's errorlevel, which is
passed on by -o pipefail. Invert the inner command: true || echo $x
这可能影响嵌套的if
s,但我不确定这里。
另一方面,这部分代码肯定检查错了:
if [ $i != Fontchanger ]; then
记住,上面那行是……
for i in $MODULESPATH/*; do
... 所以 $i
会类似于 $MODULESPATH/Fontchanger
。另外,在 ! imageless_magisk
的情况下,你 运行 超过 /sbin/.core/img
两次。
请允许我提出一个希望等效的重构代码(与嵌套 if
相比,我更喜欢失败优先的方法,并且 ||
条件比 set -e
更稳定, 和 [[
条件使用起来更安全):
if imageless_magisk; then
set -A MODULESPATHS -- /data/adb/modules /data/adb/modules_update
else
set -A MODULESPATHS -- /sbin/.core/img
fi
for MODULESPATH in "${MODULESPATHS[@]}"; do
for i in "$MODULESPATH"/*; do
[[ $i = */Fontchanger ]] || continue
[[ ! -f $i/disable ]] || continue
[[ -d $i/system/fonts ]] || continue
NAME=$(get_var "$i"/module.prop)
ui_print " [!] "
ui_print " [!] Module editing fonts detected [!] "
ui_print " [!] Module - $NAME [!] "
ui_print " [!] "
abort
done
done
你甚至可以这样做:只在最后失败,列出 所有 具有“模块编辑字体”的目录,而不是在第一次出现后失败:
if imageless_magisk; then
set -A MODULESPATHS -- /data/adb/modules /data/adb/modules_update
else
set -A MODULESPATHS -- /sbin/.core/img
fi
do_abort=0
for MODULESPATH in "${MODULESPATHS[@]}"; do
for i in "$MODULESPATH"/*; do
[[ $i = */Fontchanger ]] || continue
[[ ! -f $i/disable ]] || continue
[[ -d $i/system/fonts ]] || continue
NAME=$(get_var "$i"/module.prop)
if (( !do_abort )); then
ui_print " [!] "
ui_print " [!] Module editing fonts detected [!] "
do_abort=1
fi
ui_print " [!] Module - $NAME [!] "
done
done
if (( do_abort )); then
ui_print " [!] "
abort
fi
这些代码 应该 是 set -u
和 set -eo pipefail
安全的。如果不是,我需要一个日志(在某处添加 set -x
)来查看它在哪里中断,因为我手边没有 Magisk 环境。 shell 版本 (echo $KSH_VERSION
) 也会派上用场;大多数 Android 附带非常旧的 mksh
版本。
希望这对您有所帮助;如果没有,请随时 ping 我,我会修改我的答案。
MODULESPATH=/data/adb/modules
imageless_magisk || MODULESPATH=/sbin/.core/img
for i in $MODULESPATH*/*; do
if [[ $i != *Fontchanger ]] && [ ! -f $i/disable ] && [ -d $i/system/fonts ]; then
NAME=$(get_var $i/module.prop)
ui_print " [!] "
ui_print " [!] Module editing fonts detected [!] "
ui_print " [!] Module - $NAME [!] "
ui_print " [!] "
cancel
fi
done
这是我们想出的代码,它可以工作并且已设置 - euxo pipefail 也兼容并且可以在 magisk 环境 Android 上工作