0

解释

The Script以下运行没有修改时,它会输出(正确):

二一开始

取消注释exec下面脚本中的语句后,文件描述符 3 指向标准输出,文件描述符 4 指向标准错误:

exec 3>&1 4>&2

并且所有标准输出和标准错误都会记录到文件中,而不是打印到控制台:

# Two variances seen in the script below
exec 1>"TEST-${mode:1}.log" 2>&1  # Log Name based on subcommand
exec 1>"TEST-bootstrap.log" 2>&1  # Initial "bootstrap" log file

当 exec 语句到位时,脚本应创建三个文件(包含内容):

TEST-bootstrap.log(成功创建 - 空文件)

TEST-one.log(创建成功)

一开始

TEST-two.log(未创建)

二一开始

但相反,它似乎在第一个日志文件之后停止并且从不创建TEST-two.log. 考虑到它与exec注释掉的语句一起使用,可能会出现什么问题?

剧本

#!/bin/bash
SELFD=$(cd -P $(dirname ${0}) >/dev/null 2>&1; pwd)  # Current scripts directory
SELF=$(basename ${0})   # Current scripts name
SELFX=${SELFD}/${SELF}  # The current script exec path

fnOne() { echo "one ${*}"; }
fnTwo() { echo "two ${*}"; }

subcommand() {
    # exec 3>&1 4>&2
    # exec 1>"TEST-${mode:1}.log" 2>&1
    case "${mode}" in
        -one) fnOne   ${*}; ;;
        -two) fnTwo   ${*}; ;;
    esac
}

bootstrap() {
    # exec 3>&1 4>&2
    # exec 1>"TEST-bootstrap.log" 2>&1
    echo "START" \
        | while read line; do ${SELFX} -one ${line}; done \
        | while read line; do ${SELFX} -two ${line}; done
    exit 0
}

mode=${1}; shift

case "${mode:0:1}" in
    -) subcommand ${*} ;;
    *) bootstrap ${mode} ${*} ;;
esac
exit 0

这个脚本严格来说是我在另一个更复杂的脚本中遇到的问题的一个孤立示例。我试图使其尽可能简洁,但如果需要,我会对其进行扩展。

我正在努力完成的事情(感兴趣的人的额外阅读)

在上面,为了简单起见,The Script我使用 while 循环而不是

在我的实际脚本中,该程序将具有以下功能:list-archivesdownloadextractprocess它们将从 URL 获取档案列表,下载它们,提取它们的内容,并分别处理生成的文件。考虑到这些操作需要不同的时间,我计划并行运行它们。我的脚本bootstrap()函数看起来像这样:

# program ./myscript
list-archives "${1}" \
    | parallel myscript -download \
    | parallel myscript -extract \
    | parallel myscript -process

并会这样称呼:

./myscript "http://www.example.com"

我想要完成的是一种启动程序的方法,该程序可以并行调用它自己的函数并记录它所做的一切。这对于确定上次获取数据的时间、调试任何错误等很有用。

我还希望在使用子命令调用程序时记录日志,例如

# only list achives
>> ./myscript -list-archives "http://www.example.com"
# download this specific archive
>> ./myscript -download "http://www.example.com/archive.zip" 
# ...
4

2 回答 2

2

我认为这是问题所在:

echo "START" \
    | while read line; do ${SELFX} -one ${line}; done \
    | while read line; do ${SELFX} -two ${line}; done

第一个循环从语句中while读取。第二个循环处理第一个循环的输出。但由于脚本正在将标准输出重定向到文件,因此没有任何内容通过管道传输到第二个循环,因此它立即退出。STARTechowhilewhile

我不确定如何“解决”这个问题,因为不清楚您要完成什么。如果你想为管道中的下一个命令提供一些东西,你可以回显到 FD 3,你已经小心地使用它来保存原始标准输出。

于 2013-07-19T20:32:42.457 回答
0

我已经接受@Barmar 的回答作为答案,@Wumpus Q 留下的评论。Wumbley 将我推向了正确的方向。

解决方案是tee /dev/fd/3在 case 语句中使用,如下所示:

subcommand() {
    exec 3>&1 4>&2
    exec 1>"TEST-${mode:1}.log" 2>&1
    case "${mode}" in
        -one) fnOne   ${*}; ;;
        -two) fnTwo   ${*}; ;;
    esac | tee /dev/fd/3
}
于 2013-07-22T14:42:41.197 回答