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

时间:2018-08-15 14:50:47

标签: bash shell

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

有一个程序可以从远程服务器导出数据库,并将输出作为压缩内容发送。
我想解压缩内容,然后解析。
如果可以,请导入它,否则发送错误消息。我不想写入磁盘上的任何临时文件,所以我想直接从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"

这里的挑战是不要写入物理文件。如果是这种情况,这会更容易,但是我想尽力而为。有可能吗?

2 个答案:

答案 0 :(得分:1)

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

这是一个坏主意,原因有几个:

  • 如果数据库足够大以至于不易处理,则尝试将其放入内存中,特别是 放入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仍在运行。因此,不需要大的缓冲区任何地方(在内存中,在磁盘上的上)来存储数据库内容。

答案 1 :(得分:1)

不使用临时文件的要求似乎有误。但您可以通过读取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 '%s\n' "$result" | mysql -u root db

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

echo "$0: Import finished" >&2

对于长字符串使用shell变量并不是特别有效或优雅;绝对建议将输出捕获到临时文件中。