我正在尝试编写一个shell 脚本,它接收一个带参数的命令作为输入并运行它。
例如,我希望在cron
以下情况下使用它:
0 11 * * * my_wrapper.sh "task_name" "command arg1 arg2 arg3 ..."
Run Code Online (Sandbox Code Playgroud)
什么的细节my_wrapper.sh
无关紧要,但它是一个zsh
脚本,我希望它接收command arg1 arg2 arg3 ...
并调用它。请注意,参数可能包含单引号、双引号等。
向脚本传递和接收带有参数的命令的正确方法是什么?
在 zsh 的命令行上,@Gilles 的第一个解决方案效果很好:
#!/bin/zsh
task_name=$1
shift
"$@" > /path/to/logging_directory/$task_name
Run Code Online (Sandbox Code Playgroud)
然后> my_wrapper.sh date "%Y-%b-%d"
从命令行调用即可完成这项工作。
但是,当我尝试按如下方式使用它时cron
:
CRON_WRAPPER="/long/path/to/my_wrapper.sh"
0 11 * * * $CRON_WRAPPER "current_date.log" date "+%Y-%b-%d"
Run Code Online (Sandbox Code Playgroud)
它不起作用。
正如吉尔斯的回答所解释的,crontab
需要逃避任何%
迹象。将以上更改为:
CRON_WRAPPER="/long/path/to/my_wrapper.sh"
0 11 * * * $CRON_WRAPPER "current_date.log" date "+\%Y-\%b-\%d"
Run Code Online (Sandbox Code Playgroud)
有效。搞定。
您有两种选择:您可以传递一个带有一些参数的程序来执行,或者您可以传递一个 shell 脚本。这两个概念都可以称为\xe2\x80\x9ca命令\xe2\x80\x9d。
\n\n带有一些参数的程序采用字符串列表的形式,其中第一个是可执行文件的路径(或不包含任何斜杠的名称,可在环境变量指示的目录列表中查找PATH
)。这样做的优点是用户可以将参数传递给该命令,而不必担心引用;用户可以显式调用 shell(sh -c \xe2\x80\xa6
如果他们愿意)。如果选择此选项,请将每个字符串(程序及其参数)作为单独的参数传递给脚本。这些通常是脚本的最后一个参数(如果您希望能够传递更多参数,则需要指定一个特殊字符串作为程序结束参数标记,然后您无法将其传递给程序,除非你使语法变得更加复杂)。
0 11 * * * my_wrapper.sh "task_name" command arg1 arg2 arg3 ...\n
Run Code Online (Sandbox Code Playgroud)\n\n在你的脚本中:
\n\n#!/bin/zsh\ntask_name=$1\nshift\n"$@"\n
Run Code Online (Sandbox Code Playgroud)\n\nshell 脚本是传递给sh
程序执行的字符串。这允许用户编写任何 shell 片段,而不必显式调用 shell,并且更容易解析,因为它是单个字符串,因此是程序的单个参数。在脚本中sh
,您可以调用eval
,但不要在 zsh 中执行此操作,因为用户不会期望必须编写与 sh 语法略有不同的 zsh 语法。
0 11 * * * my_wrapper.sh "task_name" "command arg1 arg2 arg3 ..."\n
Run Code Online (Sandbox Code Playgroud)\n\n在你的脚本中:
\n\n#!/bin/zsh\ntask_name=$1\nsh -c "$2"\n
Run Code Online (Sandbox Code Playgroud)\n