【问题标题】:Passing subshell to bash function将 subshel​​l 传递给 bash 函数
【发布时间】:2019-11-15 16:32:57
【问题描述】:

我有一组 bash 日志功能,可以让我轻松地将所有输出重定向到日志文件,并在发生某些事情时退出:

#! /usr/bin/env bash

# This script is meant to be sourced

export SCRIPT=$0
if [ -z "${LOG_FILE}" ]; then
    export LOG_FILE="./log.txt"
fi

# https://stackoverflow.com/questions/11904907/redirect-stdout-and-stderr-to-function
# If the message is piped receives info, if the message is a parameter
# receives info, message
log() {
    local TYPE
    local IN
    local PREFIX
    local LINE

    TYPE="$1"
    if [ -n "$2" ]; then
        IN="$2"
    else
        if read -r LINE; then
          IN="${LINE}"
        fi

        while read -r LINE; do
          IN="${IN}\n${LINE}"
        done

        IN=$(echo -e "${IN}")
    fi

    if [ -n "${IN}" ]; then
        PREFIX=$(date +"[%X %d-%m-%y - $(basename "${SCRIPT}")] ${TYPE}: ")
        IN="$(echo "${IN}" | awk -v PREFIX="${PREFIX}" '{printf PREFIX}$0')"
        touch "${LOG_FILE}"
        echo "${IN}" >> "${LOG_FILE}"
    fi
}

# receives message as parameter or piped, logs as info
info() {
    log "( INFO )" "$@" 
}

# receives message as parameter or piped, logs as an error
error() {
    log "(ERROR )" "$@"
}

# logs error and exits
fail() {
    error "$1"
    exit 1
}

# Reroutes stdout to info and sterr to error
log_wrap()
{
    "$@" > >(info) 2> >(error)
    return $?
}

那我使用函数如下:

LOG_FILE="logging.log"
source "log_functions.sh"

info "Program started"
log_wrap some_command arg0 arg1 --kwarg=value || fail "Program failed"

哪个有效。由于log_wrap 重定向stdout 和sterr,我不希望它干扰使用管道或重定向组成的命令。如:

log_wrap echo "File content" > ~/user_file || fail "user_file could not be created."
log_wrap echo "File content" | sudo tee ~/root_file > /dev/null || fail "root_file could not be created."

所以我想要一种方法来对这些命令进行分组,以便解决它们的重定向问题,然后将其传递给log_wrap。我知道两种分组方式:

  • 子shell:它们不是用来传递的,自然是这样的:

    log_wrap ( echo "File content" > ~/user_file ) || fail "user_file could not be created."
    

    引发语法错误。

  • 大括号(分组?上下文?):在命令内部调用时,大括号被解释为参数。

    log_wrap { echo "File content" > ~/user_file } || fail "user_file could not be created."
    

    大致相当于(在我的理解中):

    log_wrap '{' echo "File content" > ~/user_file '}' || fail "user_file could not be created."
    

概括地说,我的问题是:有没有办法将命令组合(在我的例子中由重定向/管道组成)传递给 bash 函数?

【问题讨论】:

    标签: bash function pipe subshell


    【解决方案1】:

    按照它的设置方式,您只能传递 Posix 所谓的简单命令——命令名称和参数。没有像 subshel​​l 或大括号这样的复合命令将起作用。

    但是,您可以使用函数在简单的命令中运行任意代码:

    foo() { { echo "File content" > ~/user_file; } || fail "user_file could not be created."; }
    log_wrap foo
    

    您还可以考虑使用 exec 自动将包装器应用于脚本其余部分中的所有命令:

    exec > >(info) 2> >(error)
    { echo "File content" > ~/user_file; } || fail "user_file could not be created.";
    

    【讨论】:

    • exec 选项是一个有效的解决方案,但对我来说不是,因为有时我想谨慎使用它。我同意一个函数可以工作,如果可以就地定义一个lamba,它实际上会非常好。可悲的是有no built-in way to define anonymous functions。如果没有人提供更简洁的方法,我会将其标记为已接受的答案。
    • log_wrap eval '{ echo "File content" > ~/user_file; } || fail "user_file could not be created."; }',但我不推荐它
    • 我同意,我也不会使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 2013-04-20
    • 2012-04-21
    • 2017-06-03
    相关资源
    最近更新 更多