用户定义的输出重定向未按预期工作

时间:2017-07-23 06:04:44

标签: linux shell unix ksh

我正在使用KSH脚本来执行具有以下语法的二进制(程序)来正确执行:

  • myprog [-v | --verbose (optional)] [input1] [input2]

程序没有打印任何内容成功时返回退出代码0(零)。失败时,它会将ERROR消息打印到STDERR&返回exit status > 0。如果指定了-v选项,则会在成功和失败的情况下将详细信息打印到STDOUT

为了使这个可用并减少参数交换和用户控制日志记录的机会,我使用了一个ksh shell脚本来调用这个二进制文件。运行ksh shell脚本的语法如下:

  • myshell.sh [-v(可选)] [-a input1] [-b input2]

如果指定了-v选项,则ksh会将STDOUT重定向到<execution_date_time>_out.log,将STDERR重定向到<execution_date_time>_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&amp;在屏幕上打印STDOUT(即,没有发生重定向)以及在执行成功或不成功后没有创建*.log个文件(即退出状态:分别为0或> 0)。 / p>

任何人都可以帮我解决这个问题吗? 感谢。

4 个答案:

答案 0 :(得分:2)

而不是尝试将补丁重定向到命令行,只需在解析标志时重定向流。那就是:

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,但这很难解决。 (例如,错误检查更快,或在错误检查后执行test -n "$verbopt" && exec > ...或类似)

答案 1 :(得分:1)

问题是>的价值未扩展$log

我担心你需要使用条件,例如:

cmd="myprog $verbopt $arg1 $arg2"

if [ "$log" ]; then
    $cmd 1>${dateTime}_out.log 2>${dateTime}_err.log
else
    $cmd
fi

答案 2 :(得分:0)

我会使用成语exec 重定向,它运行脚本的其余部分,就好像在运行时提供了给定的重定向一样:

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 builtin print将错误消息发送到标准错误而不是标准输出。 / p>

以下是我放在一起的内容:

#!/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%FT%T的C库中。

您也可以更聪明一点,让log_flag为空或-q的字符串,将其传递给命令,并针对空字符串进行测试以确定是否为打开日志文件,但我发现逻辑更容易理解,简单的0/1值被视为布尔值。

答案 3 :(得分:-1)

查看QueryException Error Code : 904 Error Message : ORA-00904: "FIRSTNAME": invalid identifier Position : 69 命令。

替换......

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,new String[]{ Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS }, 12345);
    } else {
        // WE ALREADY HAVE PERMISSION, RUN THE MAIN FUNCTION
        shoro();
    }

}


public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    Toast.makeText(this,"salam1",Toast.LENGTH_SHORT).show();
    if ((requestCode == 12345) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
        Toast.makeText(this,"salam2",Toast.LENGTH_SHORT).show();
        // WE GOT THE PERMISSION, RUN THE MAIN FUNCTION
        try {
            shoro();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用:

eval

我不知道你的myprog $verbopt $arg1 $arg2 $log 做了什么,但这是一个使用eval myprog $verbopt $arg1 $arg2 $log 来运行myprog(有效命令)和eval(无效命令)的简单示例,重定向因此输出到log.stdout / log.stderr:

date

现在运行脚本:

date xyz