首先我不知道我是否谈论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 变量中,需要对其进行编码(如
base64
、uunencode
或其他工具(。这使得它比以前更大,并且还增加了性能开销
。但是,根据要求,坏主意代码:
#!/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 变量不是特别有效或优雅;将输出捕获到临时文件中绝对是推荐的方法。