bash 脚本 - 从标准输入读取 tarball

jay*_*ren 7 bash tar pipe stdin fifo

我有一项需要编写脚本的任务,我觉得它应该非常简单,但实际上我过得很艰难。

我有一个简短的 bash 脚本,它采用 tarball 形式的特定类型的应用程序并构建它。目前它只需要两个命令行参数:应用程序的名称和 tarball 的位置。但是我准备在多主机系统上部署构建脚本,相反,我希望这个脚本将应用程序 tarball 放在 stdin 上,这将通过 ssh 进行管道传输。例如,这是我想调用脚本的方式:

ssh build-host "/usr/local/bin/build-app.sh myapp" < /tmp/myapp.tar.gz
Run Code Online (Sandbox Code Playgroud)

当像这样调用时,构建脚本将尝试构建一个名为“myapp”的应用程序。

我希望构建脚本在读取 tarball 之前执行一些完整性检查。此外,如果健全性检查失败,它应该正常退出。所以这是我第一次尝试构建脚本的要点:

#!/bin/bash

appname=$1

# example sanity check
if [ ! -d "/apps/$appname" ]; then
    mkdir "/apps/$appname"
else
    echo "Error! The app already has been built."
    exit 1
fi

# more sanity checks...

# if passed all tests, then read stdin into tarfile
cat > "/apps/$appname/app.tar.gz"

# build app ...
Run Code Online (Sandbox Code Playgroud)

这几乎有效。问题是我不知道如何从 bash 脚本中途读取 stdin。这个cat > file技巧只有在我把它放在脚本的第一行时才有效。但我不想那样做。在脚本的第一行,没有运行任何健全性检查,甚至无法确定将 tarfile 放在哪里。我可能同时运行多个脚本实例,并且没有避免冲突的好方法。

(除此之外cat > file,我还尝试< /dev/stdin > file了类似结果非常相似的技巧。)

所以我也尝试了以下方法:

#!/bin/bash

tarball="$(cat)"
appname="$1"

# example sanity check
if [ ! -d "/apps/$appname" ]; then
    mkdir "/apps/$appname"
else
    echo "Error! The app already has been built."
    exit 1
fi

# more sanity checks...

# if passed all tests, then read stdin into tarfile
echo -n "$tarball" > "/apps/$appname/app.tar.gz"

# build app ...
Run Code Online (Sandbox Code Playgroud)

但这也很成问题,原因有二。首先,它没有用。echo,即使带有-n标志,似乎也不是为二进制数据设计的,并且生成的 tarfile 已损坏。其次,作为第一步,这需要将整个 tarball 存储为变量。这不仅比预期的要慢,即使对于 5MB 测试 tarball,而且还可能意味着高内存消耗,尤其是对于我可能会处理的较大应用程序。

我喜欢从标准输入读取 tarfile 的想法。这意味着如果 bash 脚本觉得需要中止,它可以简单地关闭管道,并且它可以允许 bash 脚本决定将所有应用程序 tarball 放在何处,而不是调用构建脚本的原始版本,后者看起来像这样:

scp /tmp/myapp.tar.gz build-host:/tmp/
ssh build-host /usr/local/bin/build-app.sh myapp /tmp/myapp.tar.gz
Run Code Online (Sandbox Code Playgroud)

由于(希望)显而易见的原因,这种调用方法存在问题。

我真的希望我可以通过读取标准输入或其他形式的管道或缓冲区来使这个 bash 脚本工作。有没有关于如何让它发挥作用的想法?

ori*_*ion 6

cat > file当你调用它,只要您没有从之前阅读和“使用了”输入流,或者关闭文件描述符,这你不应该工作不管。这是一个完全合法和正常的命令,至少在我这边是有效的。