我希望脚本能够复制自身,以便执行 cron 任务,但从脚本内部获取其位置却很难posix 中不可靠。更好的方法是将整个脚本制作成定界文档并获取它。
有没有一种优雅的 POSIX 方法来做到这一点?
到目前为止我已经尝试过,使用这个示例脚本:
#!/bin/sh
FOO='hello world'
echo "$FOO"
cat "$0"
第一种方法
它被写入/tmp/.script$$
以便脚本可以在需要时将其复制到适当的位置(busybox 未使用 编译mktemp
)。在 linux 2.6 上运行,无需/dev/fd/
或/dev/stdin
,但/proc/self/fd/
可用。
#!/bin/sh
trap '{ rm -f "/tmp/.script$$"; exit; }' EXIT INT TERM
tee "/tmp/.script$$" <<'#SCRIPT' | . /proc/self/fd/0
#!/bin/sh
FOO='hello world'
echo "$FOO"
cat "/tmp/.script$$"
#SCRIPT
这是可行的,但它源自管道,这意味着外部没有可用的变量或函数。
第二种方法
#!/bin/sh
trap '{ rm -f "/tmp/.script$$"; exit; }' EXIT INT TERM
cat > "/tmp/.script$$" <<'#SCRIPT' && . "/tmp/.script$$"
#!/bin/sh
FOO='hello world'
echo "$FOO"
cat "/tmp/.script$$"
#SCRIPT
这里的范围是固定的,但执行取决于编写脚本的成功。
第三种方法
#!/bin/sh
trap '{ rm -f "/tmp/.script$$"; exit; }' EXIT INT TERM
. /proc/self/fd/0 <<EOF
$(tee "/tmp/.script$$" <<': "SCRIPT'
#!/bin/sh
FOO='hello world'
echo "$FOO"
cat "/tmp/.script$$"
: "SCRIPT
)
EOF
#"
从功能上来说,这就是我想要的,但它相当丑陋。
什么不起作用
#!/bin/sh
trap '{ rm -f "/tmp/.script$$"; exit; }' EXIT INT TERM
{ ( tee "/tmp/.script$$" >/proc/$$/fd/0 ) <<'#SCRIPT' & } && . /proc/self/fd/0
#!/bin/sh
FOO='hello world'
echo "$FOO"
cat "/tmp/.script$$"
#SCRIPT
这只是像交互式 shell 一样等待用户输入。我明白为什么它有效,因为标准输入没有关闭,但我不确定如何打开一个新的文件描述符而不将其链接到文件(如果我无论如何都要将它链接到文件,第二种方法是清洁工)。