如何在脚本中停止tail命令

时间:2023-02-06 16:23:32

What I want to do - Start capturing the CHANGES to a log file using a custom ssh client code***. After some time (which not a fixed value and is event based), issue a command to stop tailing. This is the command I use to capture the latest changes to a log file - tail -f logfile.txt

我想做的是——使用自定义ssh客户机代码**开始捕获对日志文件的更改。一段时间后(不是固定值,而是基于事件),发出命令停止跟踪。这是我用来捕获日志文件的最新更改的命令—尾-f logfile.txt

I want to be able to end it with something like :q which I can issue from a script. I don't want to keyboard commands like ctrl + c.

我希望能够以以下内容作为结尾:q,我可以从脚本中发出q。我不想用键盘输入像ctrl + c这样的命令。

*** Pseudo code for my custom ssh client code (written in an oop language)

***为我的定制ssh客户端代码编写的伪代码(用oop语言编写)

include ssh-api
ssh = getSSHConnection();
cmd = 'cd to folder';
ssh.command(cmd);
cmd = 'tail -f log.txt';
ssh.command(cmd);
wait for special event to occur...
cmd = 'stop the tail now!'
out = ssh.command(cmd);
print "the changes made to log file were\n"  + out;

I have no write access to the server where the log file is located.

我无法对日志文件所在的服务器进行写访问。

What I tried - http://www.linuxquestions.org/questions/red-hat-31/how-to-stop-tail-f-in-scipt-529419/

我尝试的- http://www.linuxquestions.org/questions/red-hat- 31/howtostop- tail-f-in-scipt-529419/

I am not able to understand the solution there (Its in post 2). Can someone please explain the solution or suggest a different way to do this?

我无法理解那里的解决方案(在第二篇文章中)。有人能解释一下解决方案或者建议一种不同的方法吗?

Thank you.

谢谢你!

6 个解决方案

#1


16  

Inside your script you can make use of $! variable.

在您的脚本中,您可以使用$!变量。

# run tail -f in background
tail -f /var/log/sample.log > out 2>&1 &

# process id of tail command
tailpid=$!

# wait for sometime
sleep 10

# now kill the tail process
kill $tailpid

$! Expands to the process ID of the most recently executed background (asynchronous) command.

美元!展开到最近执行的后台(异步)命令的进程ID。

#2


3  

Some ways I use to work around tail -f, using .

Waiting for specific incomming:

I use this often:

我经常用这个:

sed -une '
    /DHCPOFFER/{
        s/^\(.*\) [^ ]\+ dhcpd: DHCPOFFER on \([0-9.]\+\) to \([0-9a-f:]\+\) .*$/\1 \3 -> \2/p;
        q;
    }' < <(
      tail -f /var/log/syslog
    )

With this command, I could wait for next dhcp client and get time of event, mac address and offered IP.

有了这个命令,我可以等待下一个dhcp客户端,获得事件时间、mac地址和提供的IP。

In a script:

在一个脚本:

#!/bin/bash

read rMac rIp rDate < <(
  sed -une '
    /DHCPOFFER/{
      s/^\(.*\) [^ ]\+ dhcpd: DHCPOFFER on \([0-9.]\+\) to \([0-9a-f:]\+\) .*$/\3 \2 \1/p;
      q;
    }' < <(
      tail -n0 -f /var/log/syslog
))

printf "Date:\t%s\nMac:\t%s\nIP:\t%s\n" "$rDate" $rMac $rIp

For having a script remotely stopped:

The fifo way:

fifo的方法:

mkfifo /tmp/holder
tail -f /var/log/syslog &
TailPid=$!
cat >/dev/null /tmp/holder
kill -9 $TailPid

... Then from elswhere:

…然后从其他地方:

echo >/tmp/holder

will terminate tail command.

将尾巴终止命令。

The lockpid way

lockpid方式

#!/bin/bash

[ -e /tmp/lockfile ] && exit
echo $$ >/tmp/lockfile
[ $(</tmp/lockfile) -ne $$ ] && exit
cd /var/log
tail -f syslog &
export tPid=$!
trap "kill $tPid;rm /tmp/lockfile;exit 0" 12
wait $tPid

Then, from elswhere:

然后,从其他地方:

kill -USR2 $(</tmp/lockfile)

Via SSH

The second method work fine through ssh:

第二种方法通过ssh工作良好:

ssh -T root@remoteMachine /bin/bash <<"eocmd"
    [ -e /tmp/lockfile ] && exit
    echo $$ >/tmp/lockfile
    [ $(</tmp/lockfile) -ne $$ ] && exit
    cd /var/log
    tail -f syslog &
    export tPid=$!
    trap "kill $tPid;rm /tmp/lockfile;exit 0" 12
    wait $tPid
eocmd

(care about double quote around inline script tag)

(关注内联脚本标签的双引号)

Then, from elswhere:

然后,从其他地方:

ssh root@remoteMachine '/bin/bash -c "kill -USR2 $(</tmp/lockfile)"'

(care about quote and double quote, in this order)

(按此顺序,请注意报价和双引号)

Nota about security consideration: This don't take care about security issues! Having this kind of lockfile located in /tmp could be a bad idea...

不要考虑安全性:这不会考虑安全性问题!将这种锁文件放在/tmp中可能不是一个好主意……

#3


2  

You can execute tail in the background while redirecting its output to another file (e.g. /tmp/mylog) and write the pid of the process somewhere in a pid file (e.g. ~/mytail.pid):

您可以在后台执行tail,同时将它的输出重定向到另一个文件(例如/tmp/mylog),并在pid文件(例如,~/mytail.pid)的某个地方编写该进程的pid。

tail -f logfile > /tmp/mylog & echo $! > ~/mytail.pid

Next, when you want to stop it, just execute:

接下来,当你想要停止它时,只要执行:

kill `cat ~/mytail.pid`

Then, you can see the content of the log that you gathered in the meantime (it is also a good idea to remove it later):

然后,您可以看到同时收集的日志的内容(稍后删除日志也是一个好主意):

cat /tmp/mylog
rm /tmp/mylog # just don't forget it there

#4


1  

The post #2 that you are referring to does the following: has the right answer .

你所指的第二篇文章是这样写的:有正确的答案。

It says:

它说:

tail -f /etc/httpd/logs/access_log & # This starts tailing the file in background (see & at the end)
kill `ps | grep tail | awk '{print $1;}'` # This finds the process running above tail command and kills it

You may want to introduce sleep 100 or something depending on your need, otherwise, the above two command will result in tailing just for a fraction of time before killing it.

您可能希望根据需要引入sleep 100或其他内容,否则,上面的两个命令将导致在杀死它之前仅跟踪一小段时间。

#5


1  

According to your comment to @psmears, you might use CTRL+C

根据您对@psmears的评论,您可以使用CTRL+C

@psmears - surely. that would work too. All I want to do is tell unix to tail a file, stop tailing it whenever I want, and get me the output between starting and ending the tailing. Thanks. – Borat Sagdiyev 2 days ago

@psmears——肯定。工作太。我要做的就是告诉unix跟踪一个文件,在我需要的时候停止跟踪它,并在开始和结束跟踪之间得到输出。谢谢。-博拉特·萨迪耶夫2天前。

So you can simply launch your command within the ssh parameter.

因此,只需在ssh参数中启动命令。

 ssh username@remotehost tail -f /var/log/remotelog.txt | tee result.log

And when you're done, hit CTRL+C

完成后,按CTRL+C

In the previous command I used the tee command in order to see in my terminal the new lines and store them to the file.

在前面的命令中,我使用tee命令来查看我的终端的新行,并将它们存储到文件中。

If you want it to be this to be scriptable

如果你想让它是可写的

You can do the following:

你可以做以下事情:

 ## store result to file
 FILE=result.log

 ## launch tail remote log, and store result to result.log
 ssh -n username@remote-host tail -f /path/to/remote.log > $FILE &

 ## store pid
 SSHPID=$!

 ## wait for ":q" command
 while [ "$cmd" != ":q" ]; do
    echo -ne "\n$ "
    read -n 2 cmd
 done

 ## kill ssh when you've enough
 kill $SSHPID

 ## read result
 echo "the changes made to log file were\n"
 cat $FILE

Note that if you want to separate start and stop scripts, you just have to store SSHPID in a file within the script

注意,如果您想要分离启动和停止脚本,您只需将SSHPID存储在脚本中的文件中

 echo $SSHPID > ~/.sshpid

and retrieve it from the second one

然后从第二个中取回

 SSHPID=`cat ~/.sshpid`

#6


0  

Better than a kill is to let tail exit properly:

最好的办法是让尾巴正确地离开:

tail -n0 --pid=$(($BASHPID+1)) -F logfile | sed '/special event string in the log/q'

-n0 -pid=$($BASHPID+1) -F logfile | sed '/ log/q中的特殊事件字符串

When piping, PIDs are sequential, so the pid of the tail will be $BASHPID and the pid of the sed will be $BASHPID+1. The --pid switch will cause tail to exit (properly!) when the sed command quits. Obviously this is a bashism.

当管道输送时,pid是连续的,因此尾部的pid将是$BASHPID,而sed的pid将是$BASHPID+1。当sed命令退出时,pid开关将导致tail退出(正确!)。很明显,这是一个bashism。

#1


16  

Inside your script you can make use of $! variable.

在您的脚本中,您可以使用$!变量。

# run tail -f in background
tail -f /var/log/sample.log > out 2>&1 &

# process id of tail command
tailpid=$!

# wait for sometime
sleep 10

# now kill the tail process
kill $tailpid

$! Expands to the process ID of the most recently executed background (asynchronous) command.

美元!展开到最近执行的后台(异步)命令的进程ID。

#2


3  

Some ways I use to work around tail -f, using .

Waiting for specific incomming:

I use this often:

我经常用这个:

sed -une '
    /DHCPOFFER/{
        s/^\(.*\) [^ ]\+ dhcpd: DHCPOFFER on \([0-9.]\+\) to \([0-9a-f:]\+\) .*$/\1 \3 -> \2/p;
        q;
    }' < <(
      tail -f /var/log/syslog
    )

With this command, I could wait for next dhcp client and get time of event, mac address and offered IP.

有了这个命令,我可以等待下一个dhcp客户端,获得事件时间、mac地址和提供的IP。

In a script:

在一个脚本:

#!/bin/bash

read rMac rIp rDate < <(
  sed -une '
    /DHCPOFFER/{
      s/^\(.*\) [^ ]\+ dhcpd: DHCPOFFER on \([0-9.]\+\) to \([0-9a-f:]\+\) .*$/\3 \2 \1/p;
      q;
    }' < <(
      tail -n0 -f /var/log/syslog
))

printf "Date:\t%s\nMac:\t%s\nIP:\t%s\n" "$rDate" $rMac $rIp

For having a script remotely stopped:

The fifo way:

fifo的方法:

mkfifo /tmp/holder
tail -f /var/log/syslog &
TailPid=$!
cat >/dev/null /tmp/holder
kill -9 $TailPid

... Then from elswhere:

…然后从其他地方:

echo >/tmp/holder

will terminate tail command.

将尾巴终止命令。

The lockpid way

lockpid方式

#!/bin/bash

[ -e /tmp/lockfile ] && exit
echo $$ >/tmp/lockfile
[ $(</tmp/lockfile) -ne $$ ] && exit
cd /var/log
tail -f syslog &
export tPid=$!
trap "kill $tPid;rm /tmp/lockfile;exit 0" 12
wait $tPid

Then, from elswhere:

然后,从其他地方:

kill -USR2 $(</tmp/lockfile)

Via SSH

The second method work fine through ssh:

第二种方法通过ssh工作良好:

ssh -T root@remoteMachine /bin/bash <<"eocmd"
    [ -e /tmp/lockfile ] && exit
    echo $$ >/tmp/lockfile
    [ $(</tmp/lockfile) -ne $$ ] && exit
    cd /var/log
    tail -f syslog &
    export tPid=$!
    trap "kill $tPid;rm /tmp/lockfile;exit 0" 12
    wait $tPid
eocmd

(care about double quote around inline script tag)

(关注内联脚本标签的双引号)

Then, from elswhere:

然后,从其他地方:

ssh root@remoteMachine '/bin/bash -c "kill -USR2 $(</tmp/lockfile)"'

(care about quote and double quote, in this order)

(按此顺序,请注意报价和双引号)

Nota about security consideration: This don't take care about security issues! Having this kind of lockfile located in /tmp could be a bad idea...

不要考虑安全性:这不会考虑安全性问题!将这种锁文件放在/tmp中可能不是一个好主意……

#3


2  

You can execute tail in the background while redirecting its output to another file (e.g. /tmp/mylog) and write the pid of the process somewhere in a pid file (e.g. ~/mytail.pid):

您可以在后台执行tail,同时将它的输出重定向到另一个文件(例如/tmp/mylog),并在pid文件(例如,~/mytail.pid)的某个地方编写该进程的pid。

tail -f logfile > /tmp/mylog & echo $! > ~/mytail.pid

Next, when you want to stop it, just execute:

接下来,当你想要停止它时,只要执行:

kill `cat ~/mytail.pid`

Then, you can see the content of the log that you gathered in the meantime (it is also a good idea to remove it later):

然后,您可以看到同时收集的日志的内容(稍后删除日志也是一个好主意):

cat /tmp/mylog
rm /tmp/mylog # just don't forget it there

#4


1  

The post #2 that you are referring to does the following: has the right answer .

你所指的第二篇文章是这样写的:有正确的答案。

It says:

它说:

tail -f /etc/httpd/logs/access_log & # This starts tailing the file in background (see & at the end)
kill `ps | grep tail | awk '{print $1;}'` # This finds the process running above tail command and kills it

You may want to introduce sleep 100 or something depending on your need, otherwise, the above two command will result in tailing just for a fraction of time before killing it.

您可能希望根据需要引入sleep 100或其他内容,否则,上面的两个命令将导致在杀死它之前仅跟踪一小段时间。

#5


1  

According to your comment to @psmears, you might use CTRL+C

根据您对@psmears的评论,您可以使用CTRL+C

@psmears - surely. that would work too. All I want to do is tell unix to tail a file, stop tailing it whenever I want, and get me the output between starting and ending the tailing. Thanks. – Borat Sagdiyev 2 days ago

@psmears——肯定。工作太。我要做的就是告诉unix跟踪一个文件,在我需要的时候停止跟踪它,并在开始和结束跟踪之间得到输出。谢谢。-博拉特·萨迪耶夫2天前。

So you can simply launch your command within the ssh parameter.

因此,只需在ssh参数中启动命令。

 ssh username@remotehost tail -f /var/log/remotelog.txt | tee result.log

And when you're done, hit CTRL+C

完成后,按CTRL+C

In the previous command I used the tee command in order to see in my terminal the new lines and store them to the file.

在前面的命令中,我使用tee命令来查看我的终端的新行,并将它们存储到文件中。

If you want it to be this to be scriptable

如果你想让它是可写的

You can do the following:

你可以做以下事情:

 ## store result to file
 FILE=result.log

 ## launch tail remote log, and store result to result.log
 ssh -n username@remote-host tail -f /path/to/remote.log > $FILE &

 ## store pid
 SSHPID=$!

 ## wait for ":q" command
 while [ "$cmd" != ":q" ]; do
    echo -ne "\n$ "
    read -n 2 cmd
 done

 ## kill ssh when you've enough
 kill $SSHPID

 ## read result
 echo "the changes made to log file were\n"
 cat $FILE

Note that if you want to separate start and stop scripts, you just have to store SSHPID in a file within the script

注意,如果您想要分离启动和停止脚本,您只需将SSHPID存储在脚本中的文件中

 echo $SSHPID > ~/.sshpid

and retrieve it from the second one

然后从第二个中取回

 SSHPID=`cat ~/.sshpid`

#6


0  

Better than a kill is to let tail exit properly:

最好的办法是让尾巴正确地离开:

tail -n0 --pid=$(($BASHPID+1)) -F logfile | sed '/special event string in the log/q'

-n0 -pid=$($BASHPID+1) -F logfile | sed '/ log/q中的特殊事件字符串

When piping, PIDs are sequential, so the pid of the tail will be $BASHPID and the pid of the sed will be $BASHPID+1. The --pid switch will cause tail to exit (properly!) when the sed command quits. Obviously this is a bashism.

当管道输送时,pid是连续的,因此尾部的pid将是$BASHPID,而sed的pid将是$BASHPID+1。当sed命令退出时,pid开关将导致tail退出(正确!)。很明显,这是一个bashism。