读取 shell 脚本中的行输出
Read line output in a shell script
我想从 shell 脚本中 运行 一个程序(执行时会产生日志数据)并将输出写入文本文件。我没有这样做:/
$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 脚本将其通过管道传输到我的文本文件中?我做错了什么(如果我没有做错的话)?
最终代码:
#!/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
原回答
您没有显示错误消息 — 这会有所帮助。
不过,您的问题可能是这一行:
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
双引号可以防止各种问题。
假设您解决了一系列其他问题,例如变量 FILE
和 prog
的设置。另外,我可能会使用:
exec > $FILE
初始 zap 输出文件,然后所有后续标准输出将转到该文件,因此 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>&-
'final' 代码包括以下行:
CMD="$SOCAT $DEV$BAUD STDOUT"
$CMD |
while read -r line
这可以正常工作,因为命令的参数中没有空格。这是一种常见情况,但要注意参数和文件路径中的空格。
要从进程中读取,请使用进程替换
exec 0< <( $PROG )
/bin/sh
不支持,所以用/bin/bash
代替。
要将多个单词分配给变量、引号或反斜杠空格:
PROG="$SOCAT $DEV$BAUD STDOUT"
分号在 shell 中是特殊的,引号或反斜杠:
DATE=$(date '+%d.%m.%Y;%H:%M:%S;')
此外,不需要 exec:
while ...
...
done < <( $PROG )
您甚至可以在 done
之后添加 > $FILE
而不是将每一行单独添加到文件中。
我想从 shell 脚本中 运行 一个程序(执行时会产生日志数据)并将输出写入文本文件。我没有这样做:/
$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 脚本将其通过管道传输到我的文本文件中?我做错了什么(如果我没有做错的话)?
最终代码:
#!/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
原回答
您没有显示错误消息 — 这会有所帮助。
不过,您的问题可能是这一行:
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
双引号可以防止各种问题。
假设您解决了一系列其他问题,例如变量 FILE
和 prog
的设置。另外,我可能会使用:
exec > $FILE
初始 zap 输出文件,然后所有后续标准输出将转到该文件,因此 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>&-
'final' 代码包括以下行:
CMD="$SOCAT $DEV$BAUD STDOUT"
$CMD |
while read -r line
这可以正常工作,因为命令的参数中没有空格。这是一种常见情况,但要注意参数和文件路径中的空格。
要从进程中读取,请使用进程替换
exec 0< <( $PROG )
/bin/sh
不支持,所以用/bin/bash
代替。
要将多个单词分配给变量、引号或反斜杠空格:
PROG="$SOCAT $DEV$BAUD STDOUT"
分号在 shell 中是特殊的,引号或反斜杠:
DATE=$(date '+%d.%m.%Y;%H:%M:%S;')
此外,不需要 exec:
while ...
...
done < <( $PROG )
您甚至可以在 done
之后添加 > $FILE
而不是将每一行单独添加到文件中。