The display format of Bash’s built-in time command

Check the default output format of bash‘s built-in time command:

# time

real    0m0.000s
user    0m0.000s
sys     0m0.000s

You can use -p option to output in POSIX format:

# time -p
real 0.00
user 0.00
sys 0.00

From bash source code, we know the the definitions of these two formats:

#define POSIX_TIMEFORMAT "real %2R\nuser %2U\nsys %2S"
#define BASH_TIMEFORMAT  "\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS"

To decipher the meanings of them, we need to refer bash manual:

TIMEFORMAT

The value of this parameter is used as a format string specifying how the timing information for pipelines prefixed with the time reserved word should be displayed. The ‘%’ character introduces an escape sequence that is expanded to a time value or other information. The escape sequences and their meanings are as follows; the braces denote optional portions.

%%
A literal ‘%’.

%[p][l]R
The elapsed time in seconds.

%[p][l]U
The number of CPU seconds spent in user mode.

%[p][l]S
The number of CPU seconds spent in system mode.

%P
The CPU percentage, computed as (%U + %S) / %R.

The optional p is a digit specifying the precision, the number of fractional digits after a decimal point. A value of 0 causes no decimal point or fraction to be output. At most three places after the decimal point may be specified; values of p greater than 3 are changed to 3. If p is not specified, the value 3 is used.

The optional l specifies a longer format, including minutes, of the form MMmSS.FFs. The value of p determines whether or not the fraction is included.
……

Take POSIX_TIMEFORMAT as an example: %2R denotes using second as time unit, and the precision is two digits after a decimal point; %2U and %2S are similar.

Now you can comprehend the output of time, correct? Try using BASH_TIMEFORMAT as a practice.

 

Beware “No such file or directory” error in using ksh

Check following simple script:

#!/usr/bbin/python
print("hello world!")

I misspelled python path intentionally. On Linux Bash, it reported following error:

$ ./hello.py
-bash: ./hello.py: /usr/bbin/python: bad interpreter: No such file or directory

It prompted me that “/usr/bbin/python” couldn’t be found. While on OpenBSD ksh:

$ ./hello.py
ksh: ./hello.py: No such file or directory

It gave an illusion that hello.py didn’t exist. So be careful about this error information if you use ksh.

Why doesn’t “~ /.profile” take effect in Arch Linux?

I followed Rust tutorial to install Rust on my Arch Linux, and found the Rust directory is indeed added into ~/.profile file:

$ cat ~/.profile

export PATH="$HOME/.cargo/bin:$PATH"

But after re-login, I couldn’t see Rust folder is in $PATH variable:

$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/bin:/opt/cuda/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl

It didn’t take effect!

After reading Arch Linux Bash document, I noticed the following statement which describes ~/.bash_profile:

If this file does not exist, ~/.bash_login and ~/.profile are checked in that order.

So this means that if ~/.bash_profile exists,~/.bash_login and ~/.profile won’t be checked, right? Let’s do a check:

(1) Use strace command to record the files’ names related to current user when logining.

$ strace -o out -e open bash -l
$ grep "/home/xiaonan" out
open("/home/xiaonan/.bash_profile", O_RDONLY) = 3
open("/home/xiaonan/.bashrc", O_RDONLY) = 3
open("/home/xiaonan/.bash_history", O_RDONLY) = 3
open("/home/xiaonan/.bash_history", O_RDONLY) = 3
$ exit
logout

As expected, the ~/.profile, i.e., /home/xiaonan/.profile wasn’t opened.

(2) Renamed ~/.bash_profile to pretend it didn’t exist, checked whether ~/.profile would be read:

$ mv .bash_profile .bash_profile.bak
$ strace -o out -e open bash -l
$ grep "/home/xiaonan" out
open("/home/xiaonan/.bash_profile", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/home/xiaonan/.bash_login", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/home/xiaonan/.profile", O_RDONLY) = 3
open("/home/xiaonan/.bash_history", O_RDONLY) = 3
open("/home/xiaonan/.bash_history", O_RDONLY) = 3
$ echo $PATH
/home/xiaonan/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/opt/cuda/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
$ exit
logout

As things turned out, when the ~/.bash_profile didn’t exist:

open("/home/xiaonan/.bash_profile", O_RDONLY) = -1 ENOENT (No such file or directory)

The bash would access ~/.bash_login and ~/.profile in sequence, and $HOME/.cargo/bin was added into $PATH finally.

The solution of this issue is adding following statement in ~/.bash_profile:

[[ -f ~/.profile ]] && . ~/.profile

Now it works!