【问题标题】:How do I stop tail command in script如何在脚本中停止 tail 命令
【发布时间】:2015-02-19 06:59:04
【问题描述】:

我想要做什么 - 开始使用自定义 ssh 客户端代码将更改捕获到日志文件中***。一段时间后(这不是一个固定值并且是基于事件的),发出停止拖尾的命令。这是我用来捕获日志文件最新更改的命令 - tail -f logfile.txt

我希望能够以 :q 之类的东西结束它,我可以从脚本中发出它。我不想像ctrl + c 这样的键盘命令。

*** 我的自定义 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;

我对日志文件所在的服务器没有写入权限。

我尝试了什么 - http://www.linuxquestions.org/questions/red-hat-31/how-to-stop-tail-f-in-scipt-529419/

我无法理解那里的解决方案(它在帖子 2 中)。有人可以解释一下解决方案或提出不同的方法吗?

谢谢。

【问题讨论】:

  • 如果有办法从您的 ssh 客户端发送 Ctrl+C,那对您有用吗?
  • @psmears - 当然。那也行。我要做的就是告诉 unix 跟踪一个文件,随时停止跟踪它,并在开始和结束跟踪之间获取输出。谢谢。
  • @BoratSagdiyev 当你说得到尾部开始和结束之间的输出时,你的意思是在文件中吗?
  • 赏金到期后,应将其作为副本关闭。这是一个常见问题解答,您很容易通过谷歌搜索找到答案。

标签: linux bash unix


【解决方案1】:

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

# 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

$! 扩展为最近执行的后台(异步)命令的进程 ID。

【讨论】:

  • 谢谢。实际上,我正在从另一个打开会话的代码发出“tail start”和“tail end”命令。换句话说,睡眠不是一个固定值。你的方法在这里行得通吗?
  • &1 不是文件,而是引用文件描述符=1,即标准输出。您可能需要阅读一些有关 unix 重定向的基本教程。如果您想将其保存在文件中,请使用tail -f /var/log/sample.log > /tmp/file.out 2>&1 & 假设您有权写入/tmp/file.out
  • 让我重新表述一下。理想情况下,我希望我的代码能够像 putty 那样将输出输出到控制台,即实时。目前,我只是将尾部输出放在 tmp 文件夹中,然后从那里检索它。希望这是有道理的。谢谢。
  • 实际上你可以选择不在任何文件中重定向,而只是以tail -f /var/log/sample.log & 运行命令,但你在上面写了这个命令做了一个无限的尾巴。您还可以使用pgrep tail 命令从其他腻子会话中获取tail 的进程ID。
【解决方案2】:

我用来解决tail -f 的一些方法,使用

等待特定的传入:

我经常用这个:

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

使用此命令,我可以等待下一个 dhcp 客户端 并获取事件时间、mac 地址和提供的 IP。

在脚本中:

#!/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

远程停止脚本:

先进先出方式:

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

...然后从别处:

echo >/tmp/holder

将终止tail命令。

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

然后,从别处:

kill -USR2 $(</tmp/lockfile)

通过 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

(注意内联脚本标签周围的双引号)

然后,从别处:

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

(关心引号和双引号,按此顺序)

关于安全考虑的注意事项:这里不考虑安全问题!将这种 lockfile 放在 /tmp 中可能是个坏主意...

【讨论】:

    【解决方案3】:

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

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

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

    kill `cat ~/mytail.pid`
    

    然后,您可以看到您在此期间收集的日志的内容(稍后将其删除也是一个好主意):

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

    【讨论】:

      【解决方案4】:

      您所指的帖子 #2 执行以下操作:有正确答案

      上面写着:

      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
      

      你可以根据需要引入sleep 100或其他东西,否则上面两个命令会导致在杀死它之前只拖尾一小段时间。

      【讨论】:

      • 我可以手动发出这些命令,一个接一个地进行测试吗?
      • 是的,但是您将很难做到 - 因为第一个命令将继续在您的屏幕上拖尾文件。您必须复制粘贴终端上的第二行,然后按 ENTER。如果操作正确,屏幕上的拖尾输出应该会停止。
      • 这不是一个好的解决方案 - 它会尝试杀死用户有权杀死的 所有 个尾进程......或者实际上,任何具有“尾”的进程在它的名字的任何地方!
      • 不是。我只是想解释 OP 找到的“解决方案”。编辑了我的答案以澄清这一点。
      • 只有 ps 对我不起作用。我不得不使用ps ax。所以命令现在是kill `ps ax | grep tail | awk '{print $1;}'`
      【解决方案5】:

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

      @psmears - 当然。那也行。我要做的就是告诉 unix 跟踪一个文件,随时停止跟踪它,并在开始和结束跟踪之间获取输出。谢谢。 – Borat Sagdiyev 2 天前

      所以你可以简单地在 ssh 参数中启动你的命令。

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

      完成后,点击CTRL+C

      在上一个命令中,我使用tee 命令在终端中查看新行并将它们存储到文件中。

      如果您希望它是可编写脚本的

      您可以执行以下操作:

       ## 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
      

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

       echo $SSHPID > ~/.sshpid
      

      并从第二个中检索它

       SSHPID=`cat ~/.sshpid`
      

      【讨论】:

        【解决方案6】:

        比杀戮更好的是让尾巴正确退出:

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

        管道时,PID 是连续的,所以尾部的 pid 将是 $BASHPID,而 sed 的 pid 将是 $BASHPID+1。当 sed 命令退出时, --pid 开关将导致 tail 退出(正确!)。显然,这是一个bashism。

        【讨论】:

          猜你喜欢
          • 2022-10-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-19
          • 2018-06-28
          • 2017-04-26
          相关资源
          最近更新 更多