如何写入和解析 STDIN/STDOUT/临时缓冲区?



首先我不知道我是否谈论STDIN和STDOUT,但这就是我想要实现的目标:

有一个程序可以从远程服务器导出数据库并将输出作为 gzip 内容发送。
我想解压缩内容,解析它。
如果没问题,则导入它,否则发送错误消息。我不想写入磁盘上的任何临时文件,所以我想直接从 STD 处理事情

someExportCommand > /dev/stdin #seems not work
#I want to write a message here
echo "Export database done"
cat /dev/stdin > gunzip > /dev/stdin
echo "Unzip done"
if [[ "$mycontentReadFromSTDIN" =* "password error" ]]; then
echo "error"
exit 1
fi
#I want to echo that we begin impor"
echo "Import begin"
cat /dev/stdin | mysql -u root db
#I want to echo that import finished
echo "Import finish"

这里的挑战不是写入物理文件。如果是这样的话,这更容易,但我想做艰难的方式。可能吗,怎么可能?

您所要求的文字实现(不是一个好主意,但完全按照您的要求执行(可能如下所示:

这是一个坏主意,原因如下:

  • 如果数据库足够大以至于需要打扰,那么尝试将其放入内存中,尤其是在shell 变量中是一个坏主意。
  • 为了将二进制数据放入 shell 变量中,需要对其进行编码(如base64uunencode或其他工具(。这使得它比以前更大,并且还增加了性能开销

。但是,根据要求,坏主意代码:

#!/usr/bin/env bash
set -o pipefail # if any part of a command fails, count the whole thing a failure
if exportOutputB64=$(someExportCommand | base64); then
echo "Export database done" >&2
else
echo "Export database reports failure" >&2
exit 1
fi
if exportOutputDecompressedB64=$(base64 --decode <<<"$exportOutputB64" | gunzip -c | base64); then
echo "Decompress of export done" >&2
else
echo "Decompress of export failed" >&2
exit 1
fi
unset exportOutputB64
if grep -q 'password error' < <(base64 --decode <<<"$exportOutputDecompressedB64"); then
echo "Export contains password error; considering it a failure" >&2
exit 1
fi
echo "Import begin"
mysql -u root db < <(base64 --decode <<<"$exportOutputDecompressedB64")

如果我自己写这篇文章,我只会设置一个管道来就地处理整个事情,并使用pipefail来确保在早期阶段检测到错误:

set -o pipefail
someExportCommand | gunzip -c | mysql -u root db

关于管道的重要一点是它的所有部分同时运行。因此,someExportCommand在启动时仍在mysql -u root db运行。因此,不需要在任何地方(内存中或磁盘上(使用大型缓冲区来存储数据库内容。

不使用临时文件的要求似乎非常错误;但是您可以通过读取shell变量或数组来避免它。

任何错误消息都可能在 stderr 上,而不是 stdin。但是您应该检查程序的退出状态,而不是查找它是否打印错误消息。

#!/bin/bash
result=$(someExportCommand) || exit

此时,如果出现故障,脚本将退出;否则,result包含其输出。

现在,与错误消息类似,状态消息也应打印为标准错误,而不是标准输出。常见的约定是在消息中包含脚本的名称。

echo "$0: Import begin" >&2

现在,将变量传递给mysql

mysql -u root db <<<"$result"

请注意,<<<"here string"语法是一个 Bash 功能;您不能将其与/bin/sh一起使用。如果需要脚本可移植到sh,标准解决方案仍然是使用管道;

printf '%sn' "$result" | mysql -u root db

最后,再次将状态消息打印到 stderr。

echo "$0: Import finished" >&2

对长字符串使用 shell 变量不是特别有效或优雅;将输出捕获到临时文件中绝对是推荐的方法。

最新更新