Linux 用户定义的输出重定向未按预期工作
我正在使用Linux 用户定义的输出重定向未按预期工作,linux,shell,unix,ksh,Linux,Shell,Unix,Ksh,我正在使用KSH脚本来执行二进制(程序),该二进制(程序)具有以下语法以正确执行: myprog[-v |--verbose(可选)][input1][input2] 程序不打印任何内容&成功时返回退出代码0(零)。失败时,它将错误消息打印到STDERR&返回exit status>0。如果指定了-v选项,则在成功和失败的情况下,都会将详细信息打印到STDOUT 为了使其可用并减少参数交换和用户控制日志记录的机会,我使用了一个kshshell脚本来调用这个二进制文件。运行ksh shell脚
KSH
脚本来执行二进制(程序),该二进制(程序)具有以下语法以正确执行:
myprog[-v |--verbose(可选)][input1][input2]
STDERR
&返回exit status>0
。如果指定了-v
选项,则在成功和失败的情况下,都会将详细信息打印到STDOUT
为了使其可用并减少参数交换和用户控制日志记录的机会,我使用了一个kshshell脚本来调用这个二进制文件。运行ksh shell脚本的语法如下所示:
- myshell.sh[-v(可选)][-a输入1][-b输入2]
-v
选项,则ksh将标准输出
重定向到\u out.log
和标准输出
重定向到\u err.log
。我的ksh脚本如下所示:
myshell.sh:
#! /bun/ksh
verbopt=""
log=""
arg1=""
arg2=""
dateTime=`date +%y-%m-%d_%H:%M:%S`
while getopts "va:b:" arg
do
case $arg in
v) # verbose output
verbopt="-v"
log="1>${dateTime}_out.log 2>${dateTime}_err.log"
;;
a) # Input 1
arg1=$OPTARG
;;
b) # Input 2
arg2=$OPTARG
;;
*) # usage
echo "USAGE: myshell.sh [-v] [-a input1] [-b input2]"
exit 2
;;
esac
done
if [[ -z $arg1|| -z $arg2]]
then
echo "Missing arguments"
exit 2
fi
myprog $verbopt $arg1 $arg2 $log
exit $?
这里的问题是,所有输出STDERR
&STDOUT
都打印在屏幕上(即,没有发生重定向),也没有*。日志文件是在成功或不成功执行后创建的(即,退出状态分别为0或>0)
有人能帮我吗?
谢谢。问题是
的值未展开$log
恐怕您需要为此使用条件,例如:
cmd="myprog $verbopt $arg1 $arg2"
if [ "$log" ]; then
$cmd 1>${dateTime}_out.log 2>${dateTime}_err.log
else
$cmd
fi
查看eval
命令
替换
myprog $verbopt $arg1 $arg2 $log
与:
我不知道您的myprog
做了什么,但这里有一个简单的示例,使用eval
运行date
(有效命令)和date xyz
(无效命令),相应地将输出重定向到log.stdout/log.stderr:
$ cat logout
log='1>log.stdout 2>log.stderr'
'rm' -rf log.std* > /dev/null 2>&1
echo ""
echo 'eval date ${log}'
eval date ${log}
echo ""
echo "++++++++++++ log.stdout"
cat log.stdout
echo "++++++++++++ log.stderr"
cat log.stderr
echo "++++++++++++"
'rm' -rf log.std* > /dev/null 2>&1
echo ""
echo 'eval date xyz ${log}'
eval date xyz ${log}
echo ""
echo "++++++++++++ log.stdout"
cat log.stdout
echo "++++++++++++ log.stderr"
cat log.stderr
echo "++++++++++++"
现在运行脚本:
$ logout
eval date ${log}
++++++++++++ log.stdout
Sun Jul 23 15:56:01 CDT 2017
++++++++++++ log.stderr
++++++++++++
eval date xyz ${log}
++++++++++++ log.stdout
++++++++++++ log.stderr
date: invalid date `xyz'
++++++++++++
我将使用惯用的exec
redirection,它运行脚本的其余部分,就像在运行给定的重定向时提供了重定向一样:
if need_to_log; then
exec >stdout_file 2>stderr_file
fi
this command will be logged if the above if statement was true
如果以后需要恢复stdout和stderr,以便脚本执行更多未标记的操作,则可以在子shell中运行日志部分:
(
if need_to_log; then
exec >stdout_file 2>stderr_file
fi
this command will be logged if the above if statement was true
)
this command will not be logged regardless
我还将在数组中构建该命令,这样您就可以向其中添加-v
之类的内容,而不必为每个可能的参数使用单独的变量。如果-a
和-b
参数提供给myprog
的顺序无关紧要,您可以将它们添加到数组中,而不必使用单独的变量
你可以在下面看到我的版本。除了上述更改之外,如果不记录,我也不需要获取时间戳,因为它是不必要的,并且使用ksh内置的打印将错误消息发送到standard error而不是standard out
以下是我总结的内容:
#!/usr/bin/env ksh
# new array syntax requires ksh93+; for older ksh, use this:
# set -A cmd myprog
cmd=(myprog) # build up the command to run in an array
log_flag=0 # nonzero if the command should be logged
input_a= # the two input filenames
input_b=
while getopts 'va:b:' arg; do
case $arg in
v) # verbose output
# older ksh: set -A cmd "${cmd[@]}" -v
cmd+=(-v)
log_flag=1
;;
a) # Input 1
input_a=$OPTARG
;;
b) # Input 2
input_b=$OPTARG
;;
*) # usage
print -u2 "USAGE: $0 [-v] [-a input1] [-b input2]"
exit 2
;;
esac
done
if [[ -z $input_a || -z $input_b ]]; then
print -u2 "$0: Missing arguments"
exit 2
fi
if (( log_flag )); then
timestamp=$(date +%y-%m-%d_%H:%M:%S)
exec >"${timestamp}_out.log" 2>"${timestamp}_err.log"
fi
"${cmd[@]}" "$input_a" "$input_b"
您的时间戳使用两位数的年份(%y
);组件之间的下划线是ISO 8601标准的唯一偏差,因此我建议您继续采用标准格式。这应该是%Y-%m-%dT%H:%m:%S
,或者,在具有较新版本的strftime
的C库中,%FT%T
您还可以更聪明一点,将log\u flag
设置为空字符串或-q
,将其传递给命令,并根据空字符串测试它,以确定是否打开日志文件,但是我发现简单的0/1值作为布尔值更容易遵循逻辑。与其尝试将重定向修补到命令行,不如在解析标志时重定向流。即:
while getopts "va:b:" arg
do
case $arg in
v) # verbose output
verbopt="-v"
exec 1>${dateTime}_out.log 2>${dateTime}_err.log
;;
...
您需要稍微小心一点,因为在此之后您会进行一些错误检查,并且您可能不希望以后的错误消息进入*_err.log,但这是很容易修复的。(例如,尽早进行错误检查,或在错误检查后进行测试-n“$verbopt”&&exec>…
或类似操作)强烈反对使用eval
。尤其是用户提供的字符串。这不是实现目标的安全方法。我的第一篇文章是一个如何使用eval
的简短示例;OP仍然可以在他的脚本中使用eval
,因为他实际上没有让用户提供任何潜在的邪恶命令;我已经更新了帖子,提供了一个例子,没有显示运行任何用户提供的字符串;现在快乐吗?:-)
while getopts "va:b:" arg
do
case $arg in
v) # verbose output
verbopt="-v"
exec 1>${dateTime}_out.log 2>${dateTime}_err.log
;;
...