在shell脚本中读取行输出

时间:2015-07-26 20:13:37

标签: linux bash shell sh

我想从shell脚本中运行一个程序(当它执行时生成logdata)并将输出写入文本文件。我没有这样做:/

$ prog是已执行的prog - > socat /dev/ttyUSB0,b9600 STDOUT

$ log / $ FILE只是.txt文件的路径

我有一个Perl脚本来执行此操作:

open (S,$prog) ||die "Cannot open $prog ($!)\n";
open (R,">>","$log") ||die "Cannot open logfile $log!\n";

while (<S>) {
    my $date = localtime->strftime('%d.%m.%Y;%H:%M:%S;');
    print "$date$_";
}

我尝试在像这样的shell脚本中执行此操作

#!/bin/sh

FILE=/var/log/mylogfile.log

SOCAT=/usr/bin/socat
DEV=/dev/ttyUSB0
BAUD=,b9600
PROG=$SOCAT $DEV$BAUD STDOUT

exec 3<&0
exec 0<$PROG
while read -r line
do
        DATE=`date +%d.%m.%Y;%H:%M:%S;`
        echo $DATE$line >> $FILE
done
exec 0<&3

根本不起作用......

如何使用shell脚本读取该prog的输出并将其输入到我的文本文件中?我做错了什么(如果我没有做错什么)?

最终代码:

#!/bin/sh

FILE=/var/log/mylogfile.log

SOCAT=/usr/bin/socat
DEV=/dev/ttyUSB0
BAUD=,b9600
CMD="$SOCAT $DEV$BAUD STDOUT"

$CMD |
while read -r line
do
    echo "$(date +'%d.%m.%Y;%H:%M:%S;')$line" >> $FILE
done

2 个答案:

答案 0 :(得分:1)

要从流程中读取,请使用流程替换

exec 0< <( $PROG )

/bin/sh不支持,因此请改用/bin/bash

要为变量,引号或反斜杠空格指定多个单词:

PROG="$SOCAT $DEV$BAUD STDOUT"

分号在shell中是特殊的,引用它或反斜杠:

DATE=$(date '+%d.%m.%Y;%H:%M:%S;')

此外,不需要任何执行人员:

while ...
    ...
done < <( $PROG )

您甚至可以在> $FILE之后添加done,而不是将每行分别添加到文件中。

答案 1 :(得分:0)

原始答案

您没有显示错误消息 - 这会有所帮助。

但你的问题可能就在这一行:

DATE=`date +%d.%m.%Y;%H:%M:%S;`

其中分号标记命令的结尾,并且可能没有执行任何有用的命令%H等。

您需要围绕date格式参数的引号,并且我会为此作业使用单引号:

DATE=$(date +'%d.%m.%Y;%H:%M:%S;')

甚至用以下代码替换循环体中的两行:

echo "$(date +'%d.%m.%Y;%H:%M:%S;')$line" >> $FILE

双引号可以防止各种问题。

假设您修复了许多其他问题,例如设置变量FILEprog。另外,我可能会使用:

exec > $FILE

最初删除输出文件,然后所有后续标准输出将转到该文件,因此echo行变为:

echo "$(date +'%d.%m.%Y;%H:%M:%S;')$line"

修正后的答案

这个问题最初缺少很多关键信息。它最终得到了更新,包括完整的代码。

我最初确定的问题仍然是一个问题,但您没有遇到它,因为输入重定向无法正常工作。如果您希望输入来自进程,请使用管道,或者可能process substitution。但请注意,您有#!/bin/sh作为shebang行,而/bin/sh将无法识别进程替换;要么改变shebang,要么使用管道符号。请注意,如果循环设置了在循环完成后需要访问的变量,则进程替换具有优势。

$SOCAT $DEV$BAUD STDOUT |
while read -r line
do
    …
done

while read -r line
do
    …
done < <($SOCAT $DEV$BAUD STDOUT)

请注意,您的代码包含以下行:

PROG=$SOCAT $DEV$BAUD STDOUT

这将运行$DEV$BAUD标识的命令,其参数为STDOUT,环境变量PROG设置为$SOCAT的值。那不是你想要的。

您可以使用数组:

PROG=($SOCAT $DEV$BAUD STDOUT)

然后运行:

"${PROG[@]}"

在管道中:

"${PROG[@]}" |
while read -r line
do
    …
done

或使用流程替换:

while read -r line
do
    …
done < <("${PROG[@]}")

请注意,除非在最终exec 0<&3之后有代码,否则在涉及文件描述符3的重定向中没有特别的优点。当你完成它时,你也应该关闭3:

exec 0<&3 3>&-

“最终”代码包括以下行:

CMD="$SOCAT $DEV$BAUD STDOUT"

$CMD |
while read -r line

这可以正常工作,因为命令的参数中没有空格。这是一种常见的情况,但要注意参数和文件路径中的空格。