接受来自参数或管道的输入的 Bash 函数

接受来自参数或管道的输入的 Bash 函数

我想以一种可以接受来自参数或管道的输入的方式编写以下 bash 函数:

b64decode() {
    echo "$1" | base64 --decode; echo
}

所需用途:

$ b64decode "QWxhZGRpbjpvcGVuIHNlc2FtZQo="
$ b64decode < file.txt
$ b64decode <<< "QWxhZGRpbjpvcGVuIHNlc2FtZQo="
$ echo "QWxhZGRpbjpvcGVuIHNlc2FtZQo=" | b64decode

答案1

斯特凡·查泽拉斯的回答以获得更好的解决方案。


您可以使用/dev/stdin从标准输入读取

b64decode()
{
    if (( $# == 0 )) ; then
        base64 --decode < /dev/stdin
        echo
    else
        base64 --decode <<< "$1"
        echo
    fi
}
  • $# == 0检查命令行参数的数量是否为零
  • base64 --decode <<< "$1"也可以使用herestring而不是使用echo和管道base64

答案2

这里应该只是:

b64decode() {
  if [ "$#" -gt 0 ]; then
    # concatenated arguments fed via a pipe.
    printf %s "$@" | base64 --decode
  else
    base64 --decode  # read from stdin
  fi
  ret=$?
  echo # add one newline character
  return "$ret" # return with base64's exit status to report decoding
                # errors if any.
}

无论如何,做不是使用base64 --decode < /dev/stdin。充其量(在大多数系统上)< /dev/stdin什么也不做,它只是执行相当于dup2(0,0)(将 fd 0 复制到 fd 0 上,无操作)的操作。

但在 Linux 或 Cygwin 上,< /dev/stdin这里不能正常工作。在这些系统上,打开/dev/stdin与复制 stdin 不同,它从头开始重新打开,并独立地打开与当前在 stdin 上打开的文件相同的文件。

因此,如果之前 stdin 指向某个常规文件的中间,那么之后< /dev/stdin,您将得到 stdin 现在指向的结果在开始时该文件的。如果 stdin 是管道的写入端(在正常情况下不应该),那么最终它会成为读取端。如果它是一个套接字,那么它将失败,因为套接字不能打开。如果您无权打开该文件进行读取(例如,因为权限更改或文件最初是使用不同的凭据在 stdin 上打开的),则情况相同。

返回后base64 --decode < /dev/stdin,文件中 stdin 的当前位置(用于可查找文件输入)将保持不变,而不是留在末尾(或base64停止读取的任何位置),因为base64's stdin 位于不同的位置打开文件描述

答案3

桑迪普的回答之所以有效,base64是因为该实用程序不支持多行。针对更一般情况的更一般修复

是这样的

my_function() {
    if (( ${#} == 0 )) ; then
        while read -r line ; do
            target_utility "${line}"
        done
    else
        target_utility "${@}"
    fi
}

答案4

两个都桑迪普的汤姆·罗奇的答案很有启发性并且值得赞赏,但在不同的情况下target_utility "${@}"可能代表更复杂的代码。在if和 中重复重要的代码else可能会产生不必要的问题。尽管OP的问题可能不会提出通过使用递归完美解决的问题,但其他读者的问题可能会从使用它或考虑使用包装函数中受益:

my_function() {
    if (( ${#} == 0 )) ; then
        while read -r __my_function ; do
            my_function "${__my_function}"
        done
    else
        target_utility "${@}"
    fi
}

这个答案是“接受来自参数或管道的输入的 Bash 函数”的各种可能的解决方案之一,因为 OP 指出[在评论中]这base64不是实际的问题域。因此,它不会尝试确保能够直接从文件读取输入。

根据各种评论,有人担心这个模板和类似的其他模板可能无法正确处理带有前导空格的行;IFS =之前可能需要read。事实上,shell 敏感的任何字符的存在可能需要在调用此函数之前进行特殊处理。按原样,该代码在已知不会出现前导空白且数据敏感性由发射器预先处理的情况下正常运行。

这不仅仅是教科书上的例子;它是一个例子。它用于实际的制作脚本中。 target_utility是实际代码片段的简单名称。这个答案并不假定是一个通用模板,不需要额外的开发人员智慧。

(假设用户通常会偶尔调整答案而不是逐字使用它们,这似乎是合理的。)

相关内容