我试图获得指定命令的文本输出,以某种方式修改它(例如在输出前添加前缀(并打印到文件(.txt或.log(
LOG_FILE=...
LOG_ERROR_FILE=..
command_name >> ${LOG_FILE} 2>> ${LOG_ERROR_FILE}
我想在一行中修改将返回的命令并将其打印到文件中。错误输出和常规输出的情况相同。
我是bash脚本的初学者,所以请理解。
创建一个函数来执行命令并捕获变量的sterr和stdout。
function execCommand(){
local command="$@"
{
IFS=$'n' read -r -d '' STDERR;
IFS=$'n' read -r -d '' STDOUT;
} < <((printf ' %s ' "$($command)" 1>&2) 2>&1)
}
function testCommand(){
grep foo bar
echo "return code $?"
}
execCommand testCommand
echo err: $STDERR
echo out: $STDOUT
execCommand "touch /etc/foo"
echo err: $STDERR
echo out: $STDOUT
execCommand "date"
echo err: $STDERR
echo out: $STDOUT
输出
err: grep: bar: No such file or directory
out: return code 2
err: touch: cannot touch '/etc/foo': Permission denied
out:
err:
out: Mon Jan 31 16:29:51 CET 2022
现在您可以修改$STDERR&STDOUT
execCommand testCommand && { echo "$STDERR" > err.log; echo "$STDOUT" > out.log; }
说明:看看来自madmurphy 的答案
管道|
和/或重定向>
似乎就是答案。
因此,作为一个虚假的例子来展示我的意思:为了获得命令ip a
吐出的所有接口,您可以将其通过管道传输到处理命令,并将输出重定向到文件中。
ip a | awk -F': *' '/^[0-9]/ { print $2 }' > my_file.txt
如果你想把它发送到单独的处理,你可以重定向到一个子外壳:
$ command -V cd curl bogus > >(awk '{print $NF}' > stdout.txt) 2> >(sed 's/.*s(w+):/1/' > stderr.txt)
$ cat stdout.txt
builtin
(/usr/bin/curl)
$ cat stderr.txt
bogus not found
但对于可读性来说,在单独的步骤中处理可能会更好:
$ command -V cd curl bogus >stdout.txt 2>stderr.txt
$ sed -i 's/.*s//' stdout.txt
$ sed -i 's/.*s(w+):/1/' stderr.txt
$ cat stdout.txt
builtin
(/usr/bin/curl)
$ cat stderr.txt
bogus not found
有无数种方法可以满足你们的要求,我想情况将不得不决定使用什么,但这里有一个开始。
要修改输出并将其写入文件,同时以不同的方式修改错误流并写入不同的文件,只需要适当地操作文件描述符。例如:
#!/bin/sh
# A command that writes trivial data to both stdout and stderr
cmd() {
echo 'Hello stdout!'
echo 'Hello stderr!' >&2
}
# Filter both streams and redirect to different files
{ cmd 2>&1 1>&3 | sed 's/stderr/cruel world/' > "$LOG_ERROR_FILE"; } 3>&1 |
sed 's/stdout/world/' > "$LOG_FILE"
该技术是将错误流重定向到stdout,以便它可以流入管道(2>&1
(,然后将输出流重定向到辅助文件描述符,该描述符将被重定向到另一个管道。
您可以通过将文件重定向移动到早期的exec
调用中来稍微清理一下。例如:
#!/bin/sh
cmd() {
echo 'Hello stdout!'
echo 'Hello stderr!' >&2
}
exec > "$LOG_FILE"
exec 2> "$LOG_ERROR_FILE"
# Filter both streams and redirect to different files
{ cmd 2>&1 1>&3 | sed 's/stderr/cruel world/' >&2; } 3>&1 | sed 's/stdout/world/'