我有一个bash脚本调用几个长时间运行的进程.我想根据处理原因将这些调用的输出捕获到变量中.但是,因为这些是长时间运行的进程,所以我希望rsync调用的输出实时显示在控制台中,而不是事后.
为此,我找到了一种方法,但它依赖于将文本输出到/ dev/stderr.我觉得输出到/ dev/stderr并不是一种好的做事方式.
VAR1=$(for i in {1..5}; do sleep 1; echo $i; done | tee /dev/stderr)
VAR2=$(rsync -r -t --out-format='%n%L' --delete -s /path/source1/ /path/target1 | tee /dev/stderr)
VAR3=$(rsync -r -t --out-format='%n%L' --delete -s /path/source2/ /path/target2 | tee /dev/stderr)
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,我调用rsync几次,我想看到文件名在处理时,但最后我还是想在变量中输出,因为我稍后会解析它.
是否有一种"更清洁"的方式来实现这一目标?
如果它有所作为,我使用的是Ubuntu 12.04,bash 4.2.24.
(可能与某些程序有关,不接受输入文件的进程替换?)
在一些Bash单元测试脚本中,我使用以下技巧来记录和显示命令的stdout和stderr:
command > >(tee "${stdoutF}") 2> >(tee "${stderrF}" >&2)
Run Code Online (Sandbox Code Playgroud)
此过程会向stdout生成一些输出,因此$stdoutF文件会获取一些数据.然后我运行另一个不输出任何数据的命令:
diff -r "$source" "$target" > >(tee "${stdoutF}") 2> >(tee "${stderrF}" >&2)
Run Code Online (Sandbox Code Playgroud)
但是,在运行空白测试(使用shunit-ng)之前,此过程看起来并不总是成功完成:
assertNull 'Unexpected output to stdout' "$(<"$stdoutF")"
Run Code Online (Sandbox Code Playgroud)
在100次运行测试中,这次失败了25次.
sync在测试文件空虚之前调用它是否足够:
sync
assertNull 'Unexpected output to stdout' "$(<"$stdoutF")"
Run Code Online (Sandbox Code Playgroud)
...和/或它应该通过强制执行命令的顺序来工作:
diff -r "$source" "$target" \
> >(tee "${stdoutF}"; assertNull 'Unexpected output to stdout' "$(<"$stdoutF")")
2> >(tee "${stderrF}" >&2)
Run Code Online (Sandbox Code Playgroud)
...和/或它可能以tee某种方式assertNull直接而不是文件?
更新:sync不是答案 - 请参阅下面的Gilles回复.
更新2 …
我试图理解这两个相似命令之间的差异.
aa=$(foo | bar | head -1)
read aa < <(foo | bar | head -1)
Run Code Online (Sandbox Code Playgroud)
<()需要#!/bin/bash,但这会让它变慢吗?bash或sh流程?我希望使用具有最佳性能的命令.
我有一个程序可以同时读取两个输入文件.我想从标准输入中读取该程序.我以为我会用这样的东西:
$program1 <(cat) <($program2)
Run Code Online (Sandbox Code Playgroud)
但我刚刚发现了
cat <(cat)
Run Code Online (Sandbox Code Playgroud)
产生
....
mmap2(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb758e000
read(0, 0xb758f000, 131072) = -1 EIO (Input/output error)
....
cat: -: Input/output error
Run Code Online (Sandbox Code Playgroud)
同样地,
$ cat <(read -n 1)
bash: read: read error: 0: Input/output error
Run Code Online (Sandbox Code Playgroud)
所以...... Linux无法进入read系统调用级别.那很有意思.是bash不是将stdin连接到子壳?:(
这个问题有方法解决吗?我特别需要使用进程替换(... <(...)格式),因为$program1(tail顺便说一下)需要文件,我需要od在标准输入上做一些预处理(with )才能传递给它tail- 我不能只指定/dev/stdin等等.
编辑:
我真正想要做的是从一个文件(另一个进程将写入)读取,同时我也从标准输入读取,所以我可以接受命令等.我希望我能做到
tail -f <(od -An -vtd1 -w1) <(cat fifo)
Run Code Online (Sandbox Code Playgroud)
同时从标准输入和 FIFO中读取并将其放入单个stdout流中,我可以通过awk(或类似的)运行.我知道我可以用任何脚本语言解决这个问题,但我喜欢学习如何 …
以下脚本调用另一个程序在while循环中读取其输出(请参阅Bash - 如何将输入传递给while循环并在循环结束后保留变量):
while read -r col0 col1; do
# [...]
done < <(other_program [args ...])
Run Code Online (Sandbox Code Playgroud)
如何检查退出代码other_program以查看循环是否正确执行?
我有这个shell脚本,用于备份我的系统.有一条线:
tar -Pzcpf /backups/backup.tar.gz --directory=/ --exclude=proc --exclude=sys --exclude=dev/pts --exclude=backups --exclude=var/log / 2> >(grep -v 'socket ignored' >&2)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我一直试图通过tar过滤掉烦人的,无用的"套接字忽略"错误,使用此博客文章.
我在执行时从shell获得的是:
/ bin/sysback:第45行:意外令牌附近的语法错误
>' /bin/sysback: line 45:tar -Pzcpf/backups/backup --directory =/--exclude = proc --exclude = sys --exclude = dev/pts --exclude = backups --exclude = var/log/2 >>(grep -v'cocket ignored'>&2)'
我有以下shell脚本:
cat <(echo foo)
source <(echo bar=bar)
echo $bar
Run Code Online (Sandbox Code Playgroud)
但是它在GNU bash 3.2和4.3中的工作方式不同,如下所示:
$ /bin/bash foo.sh
foo
3.2.53(1)-release
$ /usr/local/bin/bash foo.sh
foo
bar
4.3.33(1)-release
Run Code Online (Sandbox Code Playgroud)
为什么这只适用于一个版本?是bug还是添加功能?
似乎流程替换工作正常,但是在获取文件时存在问题.
如果这是预期的行为,我应该使用什么其他语法来代替source标准输入中的某些东西,以便在不同的bash版本之间兼容?
<(commands ...)在bash/zsh中将输出行为作为文件.是否存在POSIX等价物?
如何确定Bash中当前是否正在使用文件描述符?例如,如果我有一个读取,写入和关闭fd 3的脚本,例如
exec 3< <(some command here)
...
cat <&3
exec 3>&-
Run Code Online (Sandbox Code Playgroud)
什么是确保我不干扰脚本运行之前可能设置的描述符的其他目的的最佳方法?我需要将整个脚本放在子shell中吗?
我是一名C/C++程序员,一般来说非常愚蠢(至少bash做的事情让我感到困惑).我无法解决流程替代问题.
我需要定义一个全局布尔值,将它设置在循环中的某个位置,并在全局范围内使用它.有人可以用最简单的方式解释如何调整下面的代码,让我实现我的用例,简单到足以使我明天不再扭曲我的大脑来尝试掌握过程替换.
# DEFINE HERE
for i in `seq 0 ${DAEMON_COUNT}`;
do
if [ ! -d "data$i" ]; then
# SET HERE
echo "data$i does not exist. Creating...";
mkdir data$i
fi
done
# TEST AND USE HERE
Run Code Online (Sandbox Code Playgroud)
说实话,我不认为bash能胜任这个任务......下一个块看起来像这样.
echo "-------------------------------------------------------------------------------"
echo "checking the state of potentially running daemons"
for i in `seq 0 ${DAEMON_COUNT}`;
do
if [ ! -e "data$i/mongod.lock" ] ; then
echo "[no lock file] mongod process $i does not exist"
else
echo "[lock file exists] …Run Code Online (Sandbox Code Playgroud)