linux - 如何在 bash 中间接分配变量以从标准输入、文件和执行输出中获取多行数据

标签 linux bash shell scripting sh

我在这里和其他地方找到了许多片段来回答这个问题的部分内容。我什至设法以低效的方式在许多步骤中做到了这一点。如果可能的话,我真的很想找到可以执行此任务的单行执行,而不是必须分配给一个变量并复制几次才能执行该任务。

例如

executeToVar ()
{
    # Takes Arg1: NAME OF VARIABLE TO STORE IN
    # All Remaining Arguments Are Executed
    local STORE_INvar="${1}" ; shift
    eval ${STORE_INvar}=\""$( "$@" 2>&1 )"\"
}

总体上确实有效,即 $ executeToVar SOME_VAR ls -l * # 实际上会用从其余参数中获取的 SOME_VAR 命令的执行输出填充 ls -l *。但是,如果命令在末尾输出空行,(例如 - echo -e -n '\n\n123\n456\n789\n\n' 应该在开始和结束处有 2 个新行)这些将被 bash 的子执行过程剥离。我在其他类似的帖子中看到,这已通过在流的末尾添加标记“x”来解决,例如将子执行变成类似的东西:

eval ${STORE_INvar}=\""$( "$@" 2>&1 ; echo -n x )"\" # <-- ( Add echo -n x )
# and then if it wasn't an indirect reference to a var:
STORE_INvar=${STORE_INvar%x} 
# However no matter how much I play with:
eval "${STORE_INvar}"=\""${STORE_INvar%x}"\"  
# I am unable to indirectly remove the x from the end.

无论如何,我还需要 2 个其他变体,一个将 STDIN stream 分配给 var,另一个将文件的内容分配给 var,我认为这将是涉及 $( cat ${1} ) 的变体,或者 $( cat ${1:--} ) 到如果没有文件名,请给我一个“-”。但是,在我能够解决确保准确分配多行变量所需的 x 的删除之前,所有这些都不起作用。

我也试过(但没用):

IFS='' read -d '' "${STORE_INvar}" <<<"$( $@ ; echo -n x )"
eval \"'${STORE_INvar}=${!STORE_INvar%x}'\"

最佳答案

这接近于最优——但是放弃 eval

executeToVar() { local varName=$1; shift; printf -v "$1" %s "$("$@")"; }

这个公式仍然存在的一个问题是 $() 去除了尾随的换行符。如果你想防止这种情况发生,你需要在子 shell 中添加你自己的尾随字符,然后自己将其删除。

executeToVar() {
  local varName=$1; shift;
  local val="$(printf %s x; "$@"; printf %s x)"; val=${val#x}
  printf -v "$varName" %s "${val%x}"
}

如果你想从标准输入中读取所有内容到一个变量中,这特别容易:

# This requires bash 4.1 for automatic fd allocation
readToVar() {
  if [[ $2 && $2 != "-" ]]; then
    exec {read_in_fd}<"$2"              # copy from named file
  else
    exec {read_in_fd}<&0                # copy from stdin
  fi
  IFS= read -r -d '' "$1" <&$read_in_fd # read from the FD
  exec {read_in_fd}<&-                  # close that FD
}

...用作:

readToVar var < <( : "run something here to read its output byte-for-byte" )

……或者……

readToVar var filename

测试这些:

bash3-3.2$ executeToVar var printf '\n\n123\n456\n789\n\n'
bash3-3.2$ declare -p var
declare -- var="

123
456
789

"

...和...

bash4-4.3$ readToVar var2 < <(printf '\n\n123\n456\n789\n\n')
bash4-4.3$ declare -p var2
declare -- var2="

123
456
789

"

关于linux - 如何在 bash 中间接分配变量以从标准输入、文件和执行输出中获取多行数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29900839/

相关文章:

c++ - 在 C++ Linux 中获取服务状态

regex - 如何找到用于分隔字符串的正则表达式

regex - Linux shell 提取匹配模式之间的子字符串

linux - 简单的内存共享问题

linux - blktrace 测量 IO 性能

linux - 如何在 bash 中检查目录的大小并打印它?

bash - 使用 s3cmd 并行上传文件到 s3

linux - 使用一个变量作为另一个变量名称的一部分

java - 从 Java 执行源命令

shell - 如何理解 ${CONFIG+x} 中的 x