提问人:Shaun Mitchell 提问时间:10/10/2023 最后编辑:Shaun Mitchell 更新时间:10/10/2023 访问量:68
通过 bash 将字符串附加到文件而无需重定向的内置/可移植方法
Built-in/portable method of appending string to file via bash without redirection
问:
我有一个用 bash 编写的函数,旨在:debug()
- 可跨 GNU linux 机器和 MacOS 移植
- 在循环中可用,例如使用重定向的位置
while ...; do ...; done < foo
- 将消息写入 OR 指定的日志文件
/dev/stderr
$DEBUG_LOG
目前基本遵循(简体)格式:
# @description Write debug messages to $DEBUG_LOG if set, else /dev/stderr
# @usage debug <message>
function debug() {
if [[ "${DEBUG}" == "true" ]]; then
# Use $DEBUG_LOG if set, else /dev/stderr
local log_file="${DEBUG_LOG:-/dev/stderr}"
# Join all arguments using \n and prepend every line with "[debug] "
local debug_message=$(printf "%s\n" "${@}" | sed 's/^/[debug] /')
# Append the debug message to the log file
echo "${debug_message}" | dd of="${log_file}" conv=notrunc oflag=append status=none
fi
}
好奇者的完整代码
主要问题
显而易见的不是一种选择。它在场景 #2 上失败。当在循环中调用时,在函数中使用重定向将吃掉 STDIN 并中断循环。echo "${debug_message}" >> "${log_file}"
debug foo
while ... done < file.txt
debug()
由此,我确定我需要一些命令,我可以将其通过管道传输并附加到日志文件或 STDERR,并且在我尝试在 MacOS 😅 上使用它之前效果很好显然 BSD 版本不允许该选项,这对于附加到日志文件相当重要......dd
dd
oflag=append
理想的解决方案
理想情况下,会有一些基本命令,这样我就可以在不重定向的情况下执行以下操作之一:append-stuff
echo "${debug_message}" | append-stuff "${DEBUG_LOG:-/dev/stderr}"
append-stuff "${debug_message}" "${DEBUG_LOG:-/dev/stderr}"
迄今审查的方法
debug_message=$'hello world\nsome |[]& weird ch4r4ct3r$!\nfoo bar'
SED
我尝试过以下变体:
sed -e '$a '"${debug_message}" "${DEBUG_LOG:-/dev/stderr}"
# sed: -e expression #1, char 42: unterminated `s' command
sed -e '$a helloworld' /dev/stderr
# hangs
echo "${debug_message}" | sed -e '$r /dev/stdin' "${DEBUG_LOG:-/dev/stderr}"
# hangs
awk -i 就地
我玩过几种不同的变体,但它们要么打印警告和/或悬挂外壳。更重要的是,就地扩展似乎不是内置/可移植的。echo "${debug_message}" | awk -i inplace ... /dev/stdin ... /dev/stderr
DD型
echo "${debug_message}" \
| dd of="${DEBUG_LOG:-/dev/stderr}" conv=notrunc oflag=append status=none
# works, but oflag=append is not available on MacOS, and there doesn't seem
# to be an equivalent flag in the BSD version of dd
我不知道是否有像我正在寻找的合适的命令,它要么是内置的 bash,要么是标准 *nix 工具套件的一部分,人们可以合理地期望在任何盒子上找到,但如果这里有人知道这样的事情,我将不胜感激 😄append-stuff
答:
0赞
Diego Torres Milano
10/10/2023
#1
使用您自己的示例
#! /bin/bash
# @description Write debug messages to $DEBUG_LOG if set, else /dev/stderr
# @usage debug <message>
function debug() {
if [[ "${DEBUG}" == "true" ]]; then
# Use $DEBUG_LOG if set, else /dev/stderr
local log_file="${DEBUG_LOG:-/dev/stderr}"
# Join all arguments using \n and prepend every line with "[debug] "
local debug_message=$(printf "%s\n" "${@}" | sed 's/^/[debug] /')
# Append the debug message to the log file
#echo "${debug_message}" | dd of="${log_file}" conv=notrunc oflag=append status=none
echo "${debug_message}" >> "${log_file}"
fi
}
DEBUG=true
DEBUG_LOG=$(mktemp)
yes | head -5 > foo
i=5
while (( i > 0 )); do
debug "$i"
read f
printf '%s\n' "$f"
(( i-- ))
done < foo
cat "$DEBUG_LOG"
rm "$DEBUG_LOG"
你将看到调试消息
[debug] 5
[debug] 4
[debug] 3
[debug] 2
[debug] 1
印刷。
评论
0赞
shellter
10/10/2023
不会也一样好用吗?printf "[debug] %s\n" "${@}"
评论
When debug foo is called inside a while ... done < file.txt loop, using redirection inside the debug() function will eat STDIN and break the loop.
仅当 debug 函数的内容读取 stdin 时,这才成立。 不以任何方式读取 stdin。你有一个可重复的例子吗?如果你的 stdin 被其他东西吃掉了,那么修复它并使用重定向可能是最简单的前进路径。echo "${message}" >> "${file}"
f() { echo "$1" >> testfile ; } ; while read -r line ; do f "$line" ; done < <( printf '%s\n' foo bar baz )