获取定时进程的 PID,以及时间的输出

Get PID of a timed process, along with the output of time

我有这行代码:

{ time cp $PWD/my_file $PWD/new_file ; } 2> my_log.log

我需要知道执行 'cp' 命令需要多长时间,我还需要获取 'cp' 的 PID。我只想打印 'cp' 进程的 PID 并在 my_log.log 文件中获取以下内容:

<output of time> 

我试过 PID=$! 但这不提供 cp 进程的 PID。

我能想到的最简单的就是

pgrep cp

好的——来自评论:"Contents of my_log.log will be PID of the cp command followed by the timing output of the cp command":

( time cp $PWD/my_file $PWD/new_file & 2>&1; echo $! ) > my_log.log 2>&1 

首先,您需要明确地使用 /usr/bin/time,并传递选项以附加到输出文件。然后,在您要复制的文件的名称上使用 pgrepcp 会获得太多点击):

/usr/bin/time --output=my_log.log --append cp $PWD/my_file $PWD/new_file &  pgrep -f my_file > my_log.log

您可能想要更改输出格式,因为它有点难看:

18400
0.00user 0.30system 0:02.43elapsed 12%CPU (0avgtext+0avgdata 2520maxresident)k
0inputs+496424outputs (0major+141minor)pagefaults 0swaps

根据您在上面的评论中写的内容...以下是正确的答案:

下面的代码(只是一个例子):

time (sleep 10 & echo -n "$!"; wait)

会 return 像这样:

30406
real    0m10.009s
user    0m0.004s
sys 0m0.005s

你的情况:

time (cp $PWD/old_file $PWD/new_file & echo -n "$!"; wait) &>  my_log.log

会完成任务的。

我发现这个解决方案非常优雅,因为它是一个 "one liner",尽管你在时间上得到了 "completely negligible overhead"(时间将与整个子外壳相关(还有 echowait)。从睡眠命令的结果可以明显看出开销可以忽略不计。

&> 将 stdout 和 stderr 重定向到同一个文件(因此您不需要指定 1>&2)。

注意

(time sleep 10 & echo -n "$!")

您将获得 time 进程的 pid,而不是您的 sleepcp

要了解 cp 命令大约需要多长时间,您可以检查新文件大小

size=$(stat -c %s "${old_file}")
cp "${old_file}" "${new_file}" &
cp_pid=$!
while kill -0 ${cp_pid}; do
    cpsize=$(stat -c %s "${new_file}")
    echo elapsed time $(ps -p${cp_pid} -oetime=)
    echo $((100*cpsize/size)) % done so far..
    sleep 3
done

编辑:以下评论 stat -c %s "${file}" 可以替换为 du "${file}" 它是 POSIX 和更合适的命令(参见手册页)。

  • 首先,您需要将您的(定时的)cp 命令发送到后台并带有尾随 &,这样您就可以在之后检查 运行 进程启动它。 (我怀疑你已经在这样做了,但它目前没有反映在问题中)。

  • $!,包含最近启动的后台作业的 PID 的特殊变量,在本例中反映运行 subshel​​l time命令,所以我们知道是cp命令的parent进程。要获得(在本例中是唯一的)子进程:

    • 如果您的平台有非标准 pgrep 实用程序(许多 Linux 发行版和 BSD/macOS 平台附带),请使用:
      pgrep -P $!

    • 否则,请使用以下符合 POSIX 的方法:
      ps -o pid=,ppid= | awk -v ppid=$! ' == ppid { print }'

为了方便起见,使用 prgep 将它们放在一起:

# Send the timed `cp` command to the background with a trailing `&`
{ time cp "$PWD/my_file" "$PWD/new_file"; } 2> my_log.log &

# Get the `cp` comand's PID via its parent PID, $!
cpPid=$(pgrep -P $!)