将两个命令合并为一个命令

HBa*_*iri 4 command-line ps

如何将这两个命令ps aux | head -n1 ; ps aux | grep vlc合并为一个命令?我尝试使用tee命令 ( ps aux | tee >(head -n1) >(grep vlc)) 但它没有用!

Oli*_*Oli 19

所以你试图保留 PS 命令的头部(所以你可以看到标题)但只显示vlc命令。

我个人只是awk根据两个条件(行号和 VLC)使用和过滤。如果任一为真,我们输出该行:

$ ps aux | awk 'NR==1 || $11~/vlc/'
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
oli       4833  0.6  0.2 795220 62952 ?        Sl   15:37   0:00 /usr/bin/vlc
Run Code Online (Sandbox Code Playgroud)

它还有一个额外的优势,即您只运行ps一次。因为字段 11 是主要命令(不是它的任何参数),我们也不会捕获awk正在运行的命令。我们只得到 VLC 和列标题。


在侧边栏上,这样的事情应该可以工作......但不......

ps aux | tee >(head -1 >&2) | grep vlc
Run Code Online (Sandbox Code Playgroud)

您很接近,您需要通过管道输入最后一个命令,否则tee会通过 STDOUT 溢出,如果您输出到 STDOUT 然后通过管道,它很可能会被后者捕获grep。在上面我将标题输出到 STDERR (2) 以停止grep干扰它。有点hacky,但嘿嘿。

但是,是的,这仍然不起作用。原因是head关闭 STDOUT,它过滤回tee并阻止grep. 这是设计使然,因此head不会处理比需要更多的输入。您可以模拟它正在做什么awk

$ ps aux | tee >(awk 'NR==1 {print;exit}' >&2) | grep "grep"
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
Run Code Online (Sandbox Code Playgroud)

这相当于head -1. 它找到第一行然后退出。这会杀死输入缓冲区,并tee翻转出来。

这是一个在awk找到第一行后不会退出的版本。它会在每一行上继续运行(无论好坏):

$ ps aux | tee >(awk 'NR==1' >&2) | grep "grep"
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
oli      15103  0.0  0.0  11752  2236 pts/18   S+   11:32   0:00 grep --color=auto grep
Run Code Online (Sandbox Code Playgroud)

另一种选择是将输入发送到sponge. Sponge 在将其写入文件(或被重定向)之前吸收整个输入流。这停止了​​父流的头部终止,但它确实意味着输入将被反转(grep将首先输出)所以我们也将通过一个sponge实例推送它:

$ ps aux | tee >(sponge >(head -1 >&2)) | sponge >(grep "grep")
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
oli      14875  0.0  0.0  11752  2192 pts/18   S    11:19   0:00 grep --color=auto grep
Run Code Online (Sandbox Code Playgroud)

但是,虽然这两个都有效,而且您只生成ps aux一次输出,但它们仍然存在严重问题。在awk|grep两次处理一切与sponge狂欢两次缓冲的一切。

tl;dr:如果您可以像使用 一样在一个命令中处理所有内容awk,为什么不呢?


Syl*_*eau 8

您可以告诉ps只打印vlcwith的进程 ID -C

来自man ps

   -C cmdlist
          Select by command name.  This selects the processes whose
          executable name is given in cmdlist.
Run Code Online (Sandbox Code Playgroud)

例子:

$ ps u -C vlc
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
sylvain  12586  0.1  0.3 1076848 60908 ?       Sl   20:10   0:00 /usr/bin/vlc
Run Code Online (Sandbox Code Playgroud)


hee*_*ayl 7

使用bash进程替换和cat

cat <(ps aux | head -1) <(ps aux | grep '[v]lc')
Run Code Online (Sandbox Code Playgroud)

进程替换模式<()将其中的命令输出替换为文件。cat将像往常一样简单地连接文件。

例子 :

$ cat <(ps aux | head -1) <(ps aux | grep '[v]lc')
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
chayan   26031  2.3  0.4 1098532 38556 pts/31  Sl   20:45   0:00 vlc
Run Code Online (Sandbox Code Playgroud)

  • 这在本质上与 OP 的问题中所做的事情相同,但添加了一个无用的 `cat`。 (3认同)

Way*_*Yux 6

我会用

ps aux | grep -E '^USER|vlc'
Run Code Online (Sandbox Code Playgroud)

您可以添加| grep -v grep以排除 grep 行

  • 我建议搜索一些独特的东西,比如 `%MEM`、`%CPU` 而不是 `USER`,因为 `USER` 本身就是一个有效的用户名。 (3认同)

ter*_*don 6

只是告诉ps只显示输出vlc

$ ps -P $(pgrep vlc)
PID PSR TTY      STAT   TIME COMMAND
6728   2 pts/0    Sl     0:00 vlc
Run Code Online (Sandbox Code Playgroud)

pgrep列出名称与给定模式匹配的任何进程的 PID。ps 的-P开关可让您仅列出特定 PID 的信息。将两者结合为您提供ps标题和您关心的行。