我有一个 shell 脚本(A)正在被另一个脚本(B)调用。在此脚本(A)中,我创建了一些目录并移动了一些文件,作为脚本其余部分正常工作的准备工作。脚本(A)由脚本(B)以迭代方式调用,我只希望目录的创建和文件的移动仅发生一次,即在第一个循环期间。
我该怎么做才能只执行一次脚本的一部分?
答案1
有多种方法可以将此信息从调用脚本传递到被调用脚本。一种是使用参数(./script --init
vs. ./script
)或参数值(./script --init=0
vs. ./script --init=1
)。我想最简单的方法是使用环境变量:
脚本B:
init=0
while whatever; do INIT=$((init++)) ./script_A; done
脚本A:
[...]
if [ 0 -eq "$INIT" ]; then
: make preparations
fi
[...]
如果脚本 A 能够在不被脚本 B 调用的情况下运行,则必须处理丢失的变量(if
当然在语句之前):
: ${INIT:=1}
答案2
您需要一些相对独特的环境质量可供依赖。这并不容易实现 - 特别是如果您在循环中迭代调用单独的脚本并期望它每次出现时都有不同的行为(在这种情况下为什么不使用同一脚本的某些部分?)。
不管怎样,常见的做法是使用锁文件 - 或类似的东西 - 来完成这些事情。但为了做到这一点,您确实需要独特的环境。考虑以下:
sh -c 'echo "$PPID" "$$"
for i in 1 2 3 4 5
do sh -c "echo \"\$PPID\""
done'
输出
25711 28929
28929
28929
28929
28929
28929
如果您可以依赖调用者在环境变量中向您提供其 pid,$PPID
那么它可能正是您所需要的。例如:
#!/bin/sh
#script a
LOCKDIR=${TMPDIR:-/tmp}/${0##*/}.$PPID
init() { mkdir "$LOCKDIR" || exit
# do other initialization tasks
}
loop() { : do the iterable tasks here; }
[ -d "$LOCKDIR" ] || init
loop
...和...
#!/bin/sh
#script b
a='/path/to/script/a'
for stuff in $things
do "$a" "$stuff"
done
rm -rf "${TMPDIR:-/tmp}/${a##*/}.$$"
不过,说真的,我根本没有遇到过很多情况,在这种情况下,做这种事情是一个好主意——如果我迭代地调用另一个 shell 脚本,并且我必须依赖它的环境,那么我可能会将.
脚本的内容源到当前的 shell 并以这种方式运行它。我会这样做,也就是说,如果我是非常确保我正在运行的脚本是安全编写的。
答案3
我创建了一个触发器文本文件,我使用行数作为 if 语句的触发器,然后在 if 语句内编辑文本文件以在其中添加更多行。这样,无论迭代多少次,if 语句都只会被触发一次。它可以通过非常简单的代码解决。 touch Trigger.txt n=$(wc -l > Trigger.txt fi