每次更改文件时,我都会尝试查看文件并执行一次命令,理想情况下只需使用本机bash命令。
这是我所拥有的,但如何检查我是否已到达文件的开头或结尾?我意识到tail -f
没有阅读EOF,所以我怎么知道我已经到达了文件的末尾?
tail -f source_file.js | while read line || [[ -n "$line" ]];
# how do I execute a command here just **once**?
done
只要它们是本机bash命令和大约一行,就会接受不使用tail
或while read
的答案。
也许每次调用时我都可以将变量归零?
答案 0 :(得分:5)
它绝不是本机bash解决方案,但你可以使用libinotify
来做你想做的事情:
while inotifywait -qqe modify file; do
echo "file modified"
done
这会监视对file
的修改,并在它们发生时在循环内执行操作。 -qq
开关禁止程序的输出,默认情况下,每当文件发生某些事件时都会打印一条消息。
答案 1 :(得分:4)
来自男人:
<强> -f 强>
-f选项导致tail在到达文件结尾时不会停止,而是等待将其他数据附加到输入。
因此,如果您想要监视和执行操作,需要将脚本分解为两个进程
tail
(如果您希望亲自监控更改)或
perl
或python
什么可以监视文件结束并在到达时执行某些操作(例如,运行bash脚本)。bash灵魂可以基于文件修改时间
file="./file"
runcmd() {
echo "======== file $1 is changed ============"
}
#tail -f "$file" & #uncomment 3 lines is you want pesonally watch the file
#tailpid=$!
#trap "kill $tailpid;exit" 0 2 #kill the tail, when CTRL-C this script
lastmtime=0
while read -r mtime < <(stat -c '%Z' "$file")
do
if [[ $lastmtime != $mtime ]]
then
lastmtime=$mtime
runcmd "$file"
fi
sleep 1
done
添加了另一种基于标准perl的解决方案
perltail() {
#adapted from the perlfaq5
#http://perldoc.perl.org/perlfaq5.html#How-do-I-do-a-tail--f-in-perl%3f
perl -MTime::HiRes=usleep -Mstrict -Mautodie -e '
$|=1;
open my $fh, "<", "$ARGV[0]";
my $curpos;
my $eof=1;
for (;;) {
for( $curpos = tell($fh); <$fh>; $curpos =tell($fh) ) {
print;
$eof=1
}
print "=EOF-reached=\n" if $eof;
$eof=0;
usleep(1000); #adjust the microseconds
seek($fh, $curpos, 0);
}' "$1"
}
eof_action() {
echo "EOF ACTION"
printf "%s\n" "${newlines[@]}" #new lines received from the last eof
newlines=() #empty the newlines array
}
perltail "./file" | while read -r line
do
if [[ $line =~ =EOF-reached= ]]
then
eof_action
continue
fi
#do something with the received lines - if need
#for example, store new lines into variable for processing in the do_action and like
newlines+=($line)
done
普林西:
perltail
bash函数运行tail -f
的perl实现,此外,当到达文件结尾时,它会将 MARK 输出到输出,这里:=EOF-reached=
。while read
正在寻找 MARK 并仅在该标记存在的情况下执行操作 - 例如只有在文件结束时才会到达。答案 2 :(得分:1)
我不确定你做某事的确切含义“每次更改文件时”或“约一行”的实现。 tail
命令通常以面向行的方式使用,所以我想在单个write(2)
中附加到文件的500行文本是一个值得只调用一次命令的更新
但是,在几十毫秒的延迟之后会说几十行?您希望多久调用一次命令?
如果libinotify
可用,请根据Fenech先生使用它。如果您尝试使用更基本的shell实用程序,find(1)
也可用于注意一个文件何时变得比另一个文件更新。
例如,一个脚本,它监视文件,并在更新时运行提供的命令,每隔1秒轮询一次。
#!/bin/sh
[ $# -ge 2 ] || { echo "Usage: $(basename $0) <file> <cmd...>" 1>&2; exit 1; }
[ -r "$1" ] || { echo "$1: cannot read" 1>&2; exit 1; }
FILE=$1; shift
FTMP=$(mktemp /tmp/$(basename "$FILE")_tsref.XXXXXX)
trap 'rm -f "$FTMP"' EXIT
touch -r "$FILE" "$FTMP"
while true; do
FOUT=$(find "$FILE" -newer "$FTMP") || exit $?
if [ "$FOUT" = "$FILE" ]; then
touch -r "$FILE" "$FTMP"
eval "$@"
else
sleep 1
fi
done
答案 3 :(得分:1)
很多人已经写过这个问题,可能需要澄清一些原则。
如果你想在监视器处理读取行(无论是什么,例如tail
或其他任何东西)时等待EOF,你必须指定等待间隔,换句话说,被认为是&#34 ;新线&#34;在文件中。
想象:
因此,正如您所看到的,指定您为&#34;新块&#34;所考虑的时间。线条是绝对必要的。换句话说,如果您在指定的时间间隔内多次达到EOF - 则仅表示一个EOF。 (比如在100微秒内达到EOF两次)。
因此tail -f
本身使用 1秒超时作为默认值,而在GNU版本中,您可以使用-s
参数更改此值。来自文档:
-s, - sleep-interval = N
使用-f,在迭代之间休眠约N秒(默认值为1.0);同 inotify和--pid = P,每N秒至少检查一次进程P
此外,您可以在尾部的source code中查看此内容。
对于inotify
库和inotofy-tools
,原则是相同的。 (并且尾部,(取决于您的发行版)可以使用inotofylib
本身))。使用inotifylib
必须调用函数
struct inotify_event* inotifytools_next_event (int timeout)
您的程序应经常调用此函数或inotifytools_next_events()
;在调用此函数之间,inotify事件将在内核中排队,最终队列将溢出,您将错过一些事件。 (see here)。
同样,时间间隔是必不可少的(所有常用工具都默认为1秒)。
关于使用-n $line
尝试的解决方案。它无法工作,因为当到达EOF时,尾部永远不会返回空行。尾部只返回得到的最后一行,并等待新行(并在指定的时间间隔内检查它们)。
要点:
由于上述原因,只要能够接受不使用尾巴或阅读时的答案 它们是本机bash命令,大约有一行。
没有任何意义。
希望这有帮助。
答案 4 :(得分:1)
如果使用的编辑器没有使用原子保存,则可以使用
tail -f source_file.js 2>&1 > /dev/null | while read line; do echo 'do any command here'; done
答案 5 :(得分:1)
这将允许你使用tail:
while read line; do
#code goes here
done < <(tail -f $FILE)
但是,循环每行运行一次(每次更改文件时不会运行一次)。使用< <(stat -c '%Z' "$file")
与睡眠的好处是它可以捕获每一个变化。要使用stat
以任何合理的确定性来执行此操作,您必须删除sleep命令,但这会占用CPU资源。
你可以在循环中使用带有附加逻辑的全局变量来阻止主命令在&#34; x行和/或y秒内再次运行&#34;防止为每条线路运行命令,但这仍然不可靠并且很快变得麻烦。
你最好的选择是使用inotifywait
(来自inotify-tools
),因为它为文件设置了一个监听器,而不是像你一样每秒(或连续)进行轮询与stat
。
[编辑]
或者,如果某个关键字或序列在每次更新时都添加到文件中一次,只需使用if $(grep --quiet "keyword" <<< $line)
进行检查并输入您的代码在if语句中。