简体   繁体   English

如何在 macOS 上使用 zsh `tee` output 到多个管道命令?

[英]How do I `tee` output to multiple piped commands with zsh on macOS?

I am using the tmutil status command to give me the current TimeMachine backup status.我正在使用tmutil status命令给我当前的 TimeMachine 备份状态。 It gives an output of the sort它给出了 output 之类的

% tmutil status
Backup session status:
{
    BackupPhase = Copying;
    ClientID = "com.apple.backupd";
    DateOfStateChange = "2022-11-21 11:23:03 +0000";
    DestinationID = "89E08126-7132-4D14-80B4-EFD45E8C5BFC";
    FirstBackup = 1;
    Progress =     {
        Percent = "0.1640944884974286";
        TimeRemaining = 65013;
        "_raw_Percent" = "0.1640944884974286";
        "_raw_totalBytes" = 488603537408;
        bytes = 80177147549;
        files = 159679;
        totalBytes = 488603537408;
        totalFiles = 3345928;
    };
    Running = 1;
    Stopping = 0;
}

This is not JSON, though it looks a bit like it.这不是 JSON,虽然看起来有点像。

I want to report on the Percent Complete and the Time Remaining.我想报告完成百分比和剩余时间。

I can get the Percent Complete with我可以获得完成百分比

tmutil status | grep "raw_Percent" | LC_NUMERIC="C" awk -F '"' '{print "Percent Complete: " ($4 * 100) "%"} '

and I can get the Time Remaining with我可以获得剩余时间

tmutil status | grep "TimeRemaining" | awk '{print "Time Remaining: " ($3/3600) " hours"} '

How can I run tmutil once (it seems to be a little expensive), and send the output to two grep... | awk...怎么跑一次tmutil(好像有点贵),把output发给两个grep... | awk... grep... | awk... commands? grep... | awk...命令?

My understanding is that I could do我的理解是我可以做到

tmutil status | tee > (grep "raw_Percent" | LC_NUMERIC="C" awk -F '"' '{print "Percent Complete: " ($4 * 100) "%"} ') | (grep "TimeRemaining" | awk '{print "Time Remaining: " ($3/3600) " hours"} ')

with each command (pipes and all) in brackets.每个命令(管道和所有)都在括号中。

But, instead, I get但是,相反,我得到

zsh: no matches found: (grep raw_Percent | LC_NUMERIC=C awk -F " {print "Percent Complete: " ($4 * 100) "%"} )

You are trying to redirect the standard output of tee to a subshell.您正在尝试将tee的标准 output 重定向到子 shell。 What you want are two separate process substitutions, tee >(...) >(...) .您想要的是两个单独的流程替换, tee >(...) >(...) (Note the lack of a space between > and ( in each case.) (注意在每种情况下>(之间都缺少空格。)

As an aside, you don't need to use grep in either case;顺便说一句,在任何一种情况下都不需要使用grep just let awk filter the lines.只需让awk过滤这些行即可。

tmutil status | 
  tee >(LC_NUMERIC="C" awk -F '"' '/raw_Percent/ {print "Percent Complete: " ($4 * 100) "%"} ') \
      >(awk '/TimeRemaining/ {print "Time Remaining: " ($3/3600) " hours"} ')

After a bit of struggle, I figured out how to use plutil to convert the output of tmutil into JSON. (The trick is that the first line is just raw text and must be discarded, but the rest is the property-list format that plutil can parse.)经过一番努力,我想出了如何使用plutil将 tmutil 的tmutil转换为 JSON。(诀窍是第一行只是原始文本,必须丢弃,但 rest 是plutil的属性列表格式可以解析。)

# Assuming the output shown in your question
% tmutil status | sed '1d' | plutil -convert -json -o - - | jq '.Progress| ._raw_Percent, .TimeRemaining'
0.1640944884974286
65013

This makes parsing more robust, and (with jq ) provides simpler input to a single awk command, if you don't want to try your hand at producing the desired text in jq itself.这使得解析更加健壮,并且(使用jq )为单个awk命令提供更简单的输入,如果您不想尝试在jq本身中生成所需的文本。

Though zsh can handle floating-point arithmetic itself, so you probably don't even need awk .尽管zsh本身可以处理浮点运算,所以您可能甚至不需要awk For example,例如,

% tmutil status | ... | { read pct; read tr; }
% print "Percent complete: $(( tr * 100 ))%"
Percent complete: 16.409448849742862%

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM