0

I write a shell script and I want to get execution time of a command but I also redirect output of command to a file. Also, I need to get exit code of this specific command to use it in if statement. Here is what I have tried:

...
TIMEFORMAT=%R

log_file() {
  echo "$PROJECT_DIR/logs/$1_$(date +%Y%m%d_%H%M%S).log"
}    

CODE_TIME=$(time sh -c "ipython -c "%run ./foo.ipynb" > $(log_file "log_file_name") 2>&1")

CODE_RESULT=$?

echo "Code_Result: $CODE_RESULT"

if [ "$CODE_RESULT" -eq 0 ]

    ...

According to documentation of time, it returns the exit code of the command but I also execute an echo command in function. So, anyone has an idea about how can I get exit code of ipython command? Thanks.

3
  • what kind of accuracy are you looking for in the timing ... nearest minute? nearest second? nearest millisecond? if 'nearest second' is sufficient then consider accessing bash's $SECONDS variable, something simple like: start=$SECONDS; run-command; CODE_RESULT=$?; end=$SECONDS; duration=$((end-start)) Commented Feb 15, 2022 at 19:49
  • Or SECONDS=0; run-command; CODE_RESULT=$?; echo $SECONDS. Commented Feb 15, 2022 at 20:00
  • @markp-fuso @Cyrus I want to get in seconds but I'm using ShellCheck and it warns me about $SECONDS variable. So, I searched for an alternative and TIMEFORMAT=%R worked for me to get seconds. Commented Feb 16, 2022 at 9:53

2 Answers 2

6

Use time outside of the commands you want to capture:

start=$(date +%s)
# run stuff, capture the return code
echo time $(( $(date +%s) - $start ))
Sign up to request clarification or add additional context in comments.

Comments

1

Your quoting in your sample call is unusual. I would expect that

sh -c "ipython -c "%run ./foo.ipynb" > $(log_file "log_file_name") 2>&1"

is translated to

sh -c 'ipython -c %run' './foo.ipynb > somewhere/logs/log_file_name_somedate.log 2>&1'

As for the behaviour of time wrt return codes, my bash (5.1.16) behaves like this:

$ time ls "I do not exist" > $(echo newfile) 2>&1

real    0m0,004s
user    0m0,004s
sys     0m0,000s

$ echo $?
2

$ cat newfile
"I do not exist": No such file or directory (os error 2)

And wrt to redirections like this:

$ capture="$(time (ls "I do not exist" > $(echo newfile2) 2>&1) 2>&1)"

$ echo $?
2

$ echo "$capture"

real    0m0,004s
user    0m0,004s
sys     0m0,000s

$ cat newfile2
"I do not exist": No such file or directory (os error 2)

Therefore, I'd suggest you to try changing your call to:

CODE_TIME="$(time (sh -c "ipython -c '%run ./foo.ipynb' > $(log_file "log_file_name") 2>&1") 2>&1)"

CODE_RESULT=$?

4 Comments

Sorry, I forgot to add TIMEFORMAT=%R part of the script. So, it prints only real part. I will try and write the results. Thanks for you help.
Thanks a lot. It worked. Do you have any documentation about when to use " ... ", ' ... ', $( ... ), ${ ... } etc. I'm a bit confused about usages of these. Also, could you please explain why you used second 2>&1 part? Thanks.
@AHOME That's a very broad question. The first two are String Literals with the difference that with " expansions are possible (see below). The third is called Command Substitution which lets you capture and process the output of a subshell. And the last one, Shell Parameter Expansion, is essentially how you access variables.
@AHOME As for the uses of 2>&1. Here, both redirect stderr to stdout. In the first or inner case it is used to capture the output of the inner command (ls and its error message in my example), while the second or outer captures the output of the time command, which you wanted to be stored in a variable (compare to the case where I used it just once: the inner output was captured whereas the output of time was printed).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.