BASH 脚本中的 GNU Parallel with "export -f <func>" 在 Crond 时失败并出现 "Command Not Found" 错误
GNU Parallel in BASH script with "export -f <func>" failed with "Command Not Found" error when Crond
如果我在命令 shell 上以交互方式运行我的脚本,它就会工作:
$ cat ndmpcopy_cron_parallel_svlinf05.bash
#!/usr/software/bin/bash
ndmpcopy_cron_parallel() {
timestamp=`date +%Y%m%d-%H%M`
LOG=/x/eng/itarchives/ndmpcopylogs/05_/ndmpcopy_status
TSLOG=${LOG}_$timestamp
src_filer='svlinf05'
src_account='ndmp'
src_passwd='src_passwd'
dst_svm='svlinfsrc'
dst_account='vsadmin-backup'
dst_passwd='dst_passwd'
host=`hostname`
echo $host
ssh -l root $src_filer "priv set -q diag ; ndmpcopy -sa $src_account:$src_passwd -da $dst_account:$dst_passwd -i $src_filer.eng.netapp.com:/vol/ 10.56.10.161:/$dst_svm/" | tee -a $TSLOG
echo "ndmpcopy Completed: `date` "
}
export -f ndmpcopy_cron_parallel
/u/jsung/bin/parallel -j 0 --wd . --env ndmpcopy_cron_parallel --eta ndmpcopy_cron_parallel ::: local
但是,脚本失败并抱怨无法找到导出函数 ndmpcopy_cron_parallel:
$ crontab -l
40 0,2,4,6,8,10,12,14,16,18,20,22 * * * /u/jsung/bin/ndmpcopy_cron_parallel_svlinf05.bash
错误:
Subject: Cron <jsung@cycrh6svl18> /u/jsung/bin/ndmpcopy_cron_parallel_svlinf05.bash
Computers / CPU cores / Max jobs to run
1:local / 2 / 1
Computer:jobs running/jobs completed/%of started jobs/Average seconds to complete
ETA: 0s Left: 1 AVG: 0.00s local:1/0/100%/0.0s **/bin/bash: ndmpcopy_cron_parallel: command not found**
ETA: 0s Left: 0 AVG: 0.00s local:0/1/100%/0.0s
一段时间以来,我一直在四处搜索并尝试不同的东西。我什至调整了 $PATH。不知道我错过了什么。我们可以在 BASH 脚本中嵌入 GNU Parallel 并完全放入 crontab 吗?
恭喜。你已经 shell-shocked.
您的系统上安装了两个版本的 bash
:
- /bin/bash v4.1.2 较旧的未打补丁 bash
- /usr/software/bin/bash v4.2.53 一个中年 bash,针对 Shellshock
打了补丁
bash 版本三元组中的最后一个数字是补丁级别。 Shellshock 漏洞涉及多个补丁,但相关补丁是 4.1.14、4.2.50 和 4.3.27。该补丁更改了导出函数的格式,结果是:
- 如果将函数从 shellshock bash 导出到 post-shellshock bash,您将看到警告导出的函数将被拒绝。
- 如果将函数从 post-shellshock bash 导出到 shellshock bash 之前,函数导出格式将获胜'被识别,所以它会被默默地忽略。
在这两种情况下,函数都不会被导出。换句话说,如果两个 bash 版本都已 shellshock patched,或者两者都未 shellshock patched,则只能在两个 bash 版本之间导出函数。
您的脚本清楚地表明要使用哪个 bash 到 运行 它:/usr/software/bin/bash 中的那个已经打了补丁。该脚本调用 GNU parallel,然后 GNU parallel 必须启动一个或多个 subshells 才能 运行 命令。 GNU parallel 使用 SHELL
环境变量的值来找到它应该使用的 shell。
我假设在你的用户命令shell环境中,SHELL
被设置为/usr/software/bin/bash
,而在cron
执行的环境中,它被设置至 /bin/bash
。如果是这种情况,当您在 bash 提示符下尝试导出函数时不会有任何问题,但在 cron
环境中,您最终将尝试从 [=65] 导出函数=]-shellshock bash 到 pre-shellshock bash,如上所述,结果是导出被静默忽略。因此错误。
要解决这个问题,您需要确保您使用的 bash
用于 运行 命令脚本与 GNU parallel 使用的 bash
相同。例如,您可以在调用 GNU parallel 之前显式设置 shell。
export SHELL=/usr/software/bin/bash
# ...
/u/jsung/bin/parallel -j 0 --wd . --env ndmpcopy_cron_parallel --eta ndmpcopy_cron_parallel ::: local
或者您可以只为并行命令本身设置它:
SHELL=/usr/software/bin/bash /u/jsung/bin/parallel -j 0 --wd . --env ndmpcopy_cron_parallel --eta ndmpcopy_cron_parallel ::: local
正如rici所说,问题很可能是由于shellshock引起的。 Shellshock 不影响 GNU Parallel,但修复 Shellshock 的补丁破坏了使用“--env”的函数传输。
GNU Parallel 正在赶上 Bash 中的 shellshock 补丁:Bash 已使用 BASH_FUNC_myfunc()
作为导出函数的变量名,但较新的版本使用 BASH_FUNC_myfunc%%
.所以 GNU Parallel 在传递函数时需要知道这一点。
“()”版本已在 20141022 中修复,“%%”版本预计将在 20150122 中修复。它们应该可以任意组合使用。所以你的远程 Bash 不需要像本地 Bash 一样打补丁:GNU Parallel 会 "do the right thing",你也不需要改变你自己的代码。
您可以随意测试 git 版本,其中两者都是固定的:git clone git://git.savannah.gnu.org/parallel .git
如果我在命令 shell 上以交互方式运行我的脚本,它就会工作:
$ cat ndmpcopy_cron_parallel_svlinf05.bash
#!/usr/software/bin/bash
ndmpcopy_cron_parallel() {
timestamp=`date +%Y%m%d-%H%M`
LOG=/x/eng/itarchives/ndmpcopylogs/05_/ndmpcopy_status
TSLOG=${LOG}_$timestamp
src_filer='svlinf05'
src_account='ndmp'
src_passwd='src_passwd'
dst_svm='svlinfsrc'
dst_account='vsadmin-backup'
dst_passwd='dst_passwd'
host=`hostname`
echo $host
ssh -l root $src_filer "priv set -q diag ; ndmpcopy -sa $src_account:$src_passwd -da $dst_account:$dst_passwd -i $src_filer.eng.netapp.com:/vol/ 10.56.10.161:/$dst_svm/" | tee -a $TSLOG
echo "ndmpcopy Completed: `date` "
}
export -f ndmpcopy_cron_parallel
/u/jsung/bin/parallel -j 0 --wd . --env ndmpcopy_cron_parallel --eta ndmpcopy_cron_parallel ::: local
但是,脚本失败并抱怨无法找到导出函数 ndmpcopy_cron_parallel:
$ crontab -l
40 0,2,4,6,8,10,12,14,16,18,20,22 * * * /u/jsung/bin/ndmpcopy_cron_parallel_svlinf05.bash
错误:
Subject: Cron <jsung@cycrh6svl18> /u/jsung/bin/ndmpcopy_cron_parallel_svlinf05.bash
Computers / CPU cores / Max jobs to run
1:local / 2 / 1
Computer:jobs running/jobs completed/%of started jobs/Average seconds to complete
ETA: 0s Left: 1 AVG: 0.00s local:1/0/100%/0.0s **/bin/bash: ndmpcopy_cron_parallel: command not found**
ETA: 0s Left: 0 AVG: 0.00s local:0/1/100%/0.0s
一段时间以来,我一直在四处搜索并尝试不同的东西。我什至调整了 $PATH。不知道我错过了什么。我们可以在 BASH 脚本中嵌入 GNU Parallel 并完全放入 crontab 吗?
恭喜。你已经 shell-shocked.
您的系统上安装了两个版本的 bash
:
- /bin/bash v4.1.2 较旧的未打补丁 bash
- /usr/software/bin/bash v4.2.53 一个中年 bash,针对 Shellshock 打了补丁
bash 版本三元组中的最后一个数字是补丁级别。 Shellshock 漏洞涉及多个补丁,但相关补丁是 4.1.14、4.2.50 和 4.3.27。该补丁更改了导出函数的格式,结果是:
- 如果将函数从 shellshock bash 导出到 post-shellshock bash,您将看到警告导出的函数将被拒绝。
- 如果将函数从 post-shellshock bash 导出到 shellshock bash 之前,函数导出格式将获胜'被识别,所以它会被默默地忽略。
在这两种情况下,函数都不会被导出。换句话说,如果两个 bash 版本都已 shellshock patched,或者两者都未 shellshock patched,则只能在两个 bash 版本之间导出函数。
您的脚本清楚地表明要使用哪个 bash 到 运行 它:/usr/software/bin/bash 中的那个已经打了补丁。该脚本调用 GNU parallel,然后 GNU parallel 必须启动一个或多个 subshells 才能 运行 命令。 GNU parallel 使用 SHELL
环境变量的值来找到它应该使用的 shell。
我假设在你的用户命令shell环境中,SHELL
被设置为/usr/software/bin/bash
,而在cron
执行的环境中,它被设置至 /bin/bash
。如果是这种情况,当您在 bash 提示符下尝试导出函数时不会有任何问题,但在 cron
环境中,您最终将尝试从 [=65] 导出函数=]-shellshock bash 到 pre-shellshock bash,如上所述,结果是导出被静默忽略。因此错误。
要解决这个问题,您需要确保您使用的 bash
用于 运行 命令脚本与 GNU parallel 使用的 bash
相同。例如,您可以在调用 GNU parallel 之前显式设置 shell。
export SHELL=/usr/software/bin/bash
# ...
/u/jsung/bin/parallel -j 0 --wd . --env ndmpcopy_cron_parallel --eta ndmpcopy_cron_parallel ::: local
或者您可以只为并行命令本身设置它:
SHELL=/usr/software/bin/bash /u/jsung/bin/parallel -j 0 --wd . --env ndmpcopy_cron_parallel --eta ndmpcopy_cron_parallel ::: local
正如rici所说,问题很可能是由于shellshock引起的。 Shellshock 不影响 GNU Parallel,但修复 Shellshock 的补丁破坏了使用“--env”的函数传输。
GNU Parallel 正在赶上 Bash 中的 shellshock 补丁:Bash 已使用 BASH_FUNC_myfunc()
作为导出函数的变量名,但较新的版本使用 BASH_FUNC_myfunc%%
.所以 GNU Parallel 在传递函数时需要知道这一点。
“()”版本已在 20141022 中修复,“%%”版本预计将在 20150122 中修复。它们应该可以任意组合使用。所以你的远程 Bash 不需要像本地 Bash 一样打补丁:GNU Parallel 会 "do the right thing",你也不需要改变你自己的代码。
您可以随意测试 git 版本,其中两者都是固定的:git clone git://git.savannah.gnu.org/parallel .git