4
time command1 | command2

Does time apply to command1 or command1 | command2? If your answer is one of the two, how would you specify the other?

Could you explain your answer based on the grammar of bash or how the shell interprets the command?

When the shell parses the command, does it recognize time as a reserved word before recognizing | as a control operator? Does the order between recognizing time as a reserved word and recognizing | as a control operator determines whether time applies to command1 or command1 | command2?

Thanks.

Tim
  • 101,790
  • From your previous question: the accepted answer's second line is: "This is possible because the time built-in takes a pipeline as its arguments", and the third answer: "time is a shell keyword". – muru May 18 '18 at 02:26
  • @muru That is a different question. My question here is whether time applies to the pipeline or just its first component. – Tim May 18 '18 at 03:50
  • 1
    And the part of "the time built-in takes a pipeline as its arguments" you're having trouble understanding is? – muru May 18 '18 at 03:51
  • "Does the order determines whether time applies to command1 or command1 | command2?" The "order" of what? I'm writting an answer so I'd want to know what you meant by this. – nxnev May 18 '18 at 04:11

1 Answers1

8
time command1 | command2

Does time apply to command1 or command1 | command2?

time is usually implemented in two ways: as an external command and as an internal feature of a given shell (I say "feature" because it depends on how the shell implements it, though I've only seen it as a reserved word). So, assuming there's at least an external time on the system, the actual answer depends on which shell the user is running and, if applicable, how time is implemented in such shell.

According to the tags you are using Bash as your shell, which has an internal time, and I'll assume GNU time as the external one for simplicity's sake.

Bash time:

  • Is a reserved word.
  • It applies to entire pipelines.
  • It can be used with internal commands/functions/reserved words.

GNU time:

  • Is an external command.
  • It applies to simple commands.
  • It cannot be used with internal commands/functions/reserved words unless these were invoked within a shell.

In your specific scenario, as you are running Bash, time applies to command1 | command2. If you were using a shell without an internal time but an external time is present on the system, it would apply to command1.


Q: If your answer is one of the two, how would you specify the other?

Applying time to command1 within Bash:

  • Using { … } to limit time's scope:

    { time command1; } | command2
    
  • Running the external time command:

    # Using the `command` builtin
    command time command1 | command2
    
    # Using `env`
    env time command1 | command2
    
    # Escaping/quoting the `time` word
    \time command1 | command2
    'time' command1 | command2
    
    # Explicitly running the external `time` command
    /usr/bin/time command1 | command2
    

Applying time to command1 | command2 with GNU time:

  • Placing the pipeline in an external file and running it:

    time ./script.sh
    
  • Invoking a shell and running the pipeline within it:

    time sh -c 'command1 | command2'
    

Q: Could you explain your answer based on the grammar of bash or how the shell interprets the command?

Bash documents its time in the 3.2.2 Pipelines chapter of its manual:

The format for a pipeline is

[time [-p]] [!] command1 [ | or |& command2 ] …

The reserved word time causes timing statistics to be printed for the pipeline once it finishes.

GNU time documentation is available via info time and man time:

The format of the time command is:

time [option...] COMMAND [ARG...]

time runs the program COMMAND, with any given arguments ARG.... When COMMAND finishes, time displays information about resources used by COMMAND.

POSIX documents the standard time, which is the base for many time implementations:

SYNOPSIS

time [-p] utility [argument...]

DESCRIPTION

The time utility shall invoke the utility named by the utility operand with arguments supplied as the argument operands and write a message to standard error that lists timing statistics for the utility.

When time is used as part of a pipeline, the times reported are unspecified, except when it is the sole command within a grouping command (see Grouping Commands) in that pipeline.

RATIONALE

In the KornShell, time is a shell reserved word that can be used to time an entire pipeline, rather than just a simple command. The POSIX definition has been worded to allow this implementation.

The term utility is used, rather than command, to highlight the fact that shell compound commands, pipelines, special built-ins, and so on, cannot be used directly. However, utility includes user application programs and shell scripts, not just the standard utilities.


Q: When the shell parses the command, does it recognize time as a reserved word before recognizing | as a control operator?

While Bash's manual does not explicitly mention this information, POSIX clearly states the order of recognition:

2.10.1 Shell Grammar Lexical Conventions

The input language to the shell must be first recognized at the character level. The resulting tokens shall be classified by their immediate context according to the following rules (applied in order). These rules shall be used to determine what a "token" is that is subject to parsing at the token level. The rules for token recognition in Token Recognition shall apply.

  1. If the token is an operator, the token identifier for that operator shall result.
  2. If the string consists solely of digits and the delimiter character is one of < or >, the token identifier IO_NUMBER shall be returned.
  3. Otherwise, the token identifier TOKEN results.

Further distinction on TOKEN is context-dependent. It may be that the same TOKEN yields WORD, a NAME, an ASSIGNMENT_WORD, or one of the reserved words below, dependent upon the context.

In short: operators are recognized before reserved words.


Q: Does the order between recognizing time as a reserved word and recognizing | as a control operator determines whether time applies to command1 or command1 | command2?

Not really, even if time is keep as a reserved word it could be programmed to apply to simple commands instead of entire pipelines (though I don't know any shell which has done this). What matters is how time is implemented, not its order of recognition.

nxnev
  • 3,654
  • 1
    As I noted in another comment, POSIX allows time to be a keyword. – muru May 18 '18 at 06:14
  • 1
    Isn't command also POSIX? Also, in Bash, you could quote the keyword, so it won't recognize it as such: \time foo runs the external command time – ilkkachu May 18 '18 at 06:16
  • @muru Yes, but my point is that POSIX does not require time to be a keyword. In the same page both you and I linked says: "When time is used as part of a pipeline, the times reported are unspecified, except when it is the sole command within a grouping command in that pipeline". And, in the "unspecified" definition: "The value or behavior may vary among implementations that conform to POSIX.1-2017. An application should not rely on the existence or validity of the value or behavior.". That's why I wrote: "In shells without a time reserved word, time applies to command1". – nxnev May 18 '18 at 06:36
  • @nxnev that maybe your point, but you have repeatedly said that POSIX time has to be external. My point is that POSIX makes no such requirement. – muru May 18 '18 at 06:38
  • @ilkkachu 1) command is POSIX, but IMHO using that workaround in a shell where time is not a keyword but an external command is redundant; using it in Bash (and KSH, and ZSH, ...) makes more sense. 2) That's right, just added that example. Thanks! – nxnev May 18 '18 at 06:38
  • 1
    @muru It may be a bit late but yes, you're right. I rewrote the answer to correct this issue. Feel free to edit the answer or leave another comment if this correction is not enough or some others errors arise. – nxnev Nov 07 '18 at 14:49
  • Excellent answer. – Hashim Aziz Dec 01 '19 at 21:50