Date, arithmetic, and ternary operator in one line

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












1















I have a simple code to ensure a script takes at least x seconds (500 here) on Ubuntu



t1=$(date +%s)
# script is here
t2=$(date +%s)
let "t = 500 - $t2 + $t1"
(( t = t>0 ? t : 1 ))
sleep $t


The code works perfectly, but I believe my coding is not efficient, and these three lines



t2=$(date +%s)
let "t = 500 - $t2 + $t1"
(( t = t>0 ? t : 1 ))


should be expressed in one single line. My question is how to improve the code.










share|improve this question
























  • Is this a Linux platform, or some UNIX? (More specifically, do you have GNU date?)

    – roaima
    Feb 4 at 21:48







  • 2





    There is much to be said for not sacrificing readability for perceived efficiency. If you compress that all into an inscrutable one-liner running as a subshell expansion as a parameter for sleep, how are you going to unravel that when someone calls you at 4 in the morning the day after a most raucous party to debug it when it goes sideways?

    – DopeGhoti
    Feb 4 at 21:53






  • 1





    You could lose the t and t2 entirely, but make sure your phone is switched off at 4am. sleep $( printf "%dn" $(( 500 - ($(date +%s) - t1) )) | sed 's/^-.*/1/' )

    – roaima
    Feb 4 at 22:01







  • 1





    @roaima Sorry for being vague. I updated the question. I haven't got stuck anywhere. I just want to improve my code, as I believe it is not the efficient way.

    – Googlebot
    Feb 4 at 22:01











  • @DopeGhoti very good point indeed.

    – Googlebot
    Feb 4 at 22:02















1















I have a simple code to ensure a script takes at least x seconds (500 here) on Ubuntu



t1=$(date +%s)
# script is here
t2=$(date +%s)
let "t = 500 - $t2 + $t1"
(( t = t>0 ? t : 1 ))
sleep $t


The code works perfectly, but I believe my coding is not efficient, and these three lines



t2=$(date +%s)
let "t = 500 - $t2 + $t1"
(( t = t>0 ? t : 1 ))


should be expressed in one single line. My question is how to improve the code.










share|improve this question
























  • Is this a Linux platform, or some UNIX? (More specifically, do you have GNU date?)

    – roaima
    Feb 4 at 21:48







  • 2





    There is much to be said for not sacrificing readability for perceived efficiency. If you compress that all into an inscrutable one-liner running as a subshell expansion as a parameter for sleep, how are you going to unravel that when someone calls you at 4 in the morning the day after a most raucous party to debug it when it goes sideways?

    – DopeGhoti
    Feb 4 at 21:53






  • 1





    You could lose the t and t2 entirely, but make sure your phone is switched off at 4am. sleep $( printf "%dn" $(( 500 - ($(date +%s) - t1) )) | sed 's/^-.*/1/' )

    – roaima
    Feb 4 at 22:01







  • 1





    @roaima Sorry for being vague. I updated the question. I haven't got stuck anywhere. I just want to improve my code, as I believe it is not the efficient way.

    – Googlebot
    Feb 4 at 22:01











  • @DopeGhoti very good point indeed.

    – Googlebot
    Feb 4 at 22:02













1












1








1








I have a simple code to ensure a script takes at least x seconds (500 here) on Ubuntu



t1=$(date +%s)
# script is here
t2=$(date +%s)
let "t = 500 - $t2 + $t1"
(( t = t>0 ? t : 1 ))
sleep $t


The code works perfectly, but I believe my coding is not efficient, and these three lines



t2=$(date +%s)
let "t = 500 - $t2 + $t1"
(( t = t>0 ? t : 1 ))


should be expressed in one single line. My question is how to improve the code.










share|improve this question
















I have a simple code to ensure a script takes at least x seconds (500 here) on Ubuntu



t1=$(date +%s)
# script is here
t2=$(date +%s)
let "t = 500 - $t2 + $t1"
(( t = t>0 ? t : 1 ))
sleep $t


The code works perfectly, but I believe my coding is not efficient, and these three lines



t2=$(date +%s)
let "t = 500 - $t2 + $t1"
(( t = t>0 ? t : 1 ))


should be expressed in one single line. My question is how to improve the code.







bash shell-script arithmetic






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 4 at 22:18









jimmij

31.9k874108




31.9k874108










asked Feb 4 at 21:42









GooglebotGooglebot

499623




499623












  • Is this a Linux platform, or some UNIX? (More specifically, do you have GNU date?)

    – roaima
    Feb 4 at 21:48







  • 2





    There is much to be said for not sacrificing readability for perceived efficiency. If you compress that all into an inscrutable one-liner running as a subshell expansion as a parameter for sleep, how are you going to unravel that when someone calls you at 4 in the morning the day after a most raucous party to debug it when it goes sideways?

    – DopeGhoti
    Feb 4 at 21:53






  • 1





    You could lose the t and t2 entirely, but make sure your phone is switched off at 4am. sleep $( printf "%dn" $(( 500 - ($(date +%s) - t1) )) | sed 's/^-.*/1/' )

    – roaima
    Feb 4 at 22:01







  • 1





    @roaima Sorry for being vague. I updated the question. I haven't got stuck anywhere. I just want to improve my code, as I believe it is not the efficient way.

    – Googlebot
    Feb 4 at 22:01











  • @DopeGhoti very good point indeed.

    – Googlebot
    Feb 4 at 22:02

















  • Is this a Linux platform, or some UNIX? (More specifically, do you have GNU date?)

    – roaima
    Feb 4 at 21:48







  • 2





    There is much to be said for not sacrificing readability for perceived efficiency. If you compress that all into an inscrutable one-liner running as a subshell expansion as a parameter for sleep, how are you going to unravel that when someone calls you at 4 in the morning the day after a most raucous party to debug it when it goes sideways?

    – DopeGhoti
    Feb 4 at 21:53






  • 1





    You could lose the t and t2 entirely, but make sure your phone is switched off at 4am. sleep $( printf "%dn" $(( 500 - ($(date +%s) - t1) )) | sed 's/^-.*/1/' )

    – roaima
    Feb 4 at 22:01







  • 1





    @roaima Sorry for being vague. I updated the question. I haven't got stuck anywhere. I just want to improve my code, as I believe it is not the efficient way.

    – Googlebot
    Feb 4 at 22:01











  • @DopeGhoti very good point indeed.

    – Googlebot
    Feb 4 at 22:02
















Is this a Linux platform, or some UNIX? (More specifically, do you have GNU date?)

– roaima
Feb 4 at 21:48






Is this a Linux platform, or some UNIX? (More specifically, do you have GNU date?)

– roaima
Feb 4 at 21:48





2




2





There is much to be said for not sacrificing readability for perceived efficiency. If you compress that all into an inscrutable one-liner running as a subshell expansion as a parameter for sleep, how are you going to unravel that when someone calls you at 4 in the morning the day after a most raucous party to debug it when it goes sideways?

– DopeGhoti
Feb 4 at 21:53





There is much to be said for not sacrificing readability for perceived efficiency. If you compress that all into an inscrutable one-liner running as a subshell expansion as a parameter for sleep, how are you going to unravel that when someone calls you at 4 in the morning the day after a most raucous party to debug it when it goes sideways?

– DopeGhoti
Feb 4 at 21:53




1




1





You could lose the t and t2 entirely, but make sure your phone is switched off at 4am. sleep $( printf "%dn" $(( 500 - ($(date +%s) - t1) )) | sed 's/^-.*/1/' )

– roaima
Feb 4 at 22:01






You could lose the t and t2 entirely, but make sure your phone is switched off at 4am. sleep $( printf "%dn" $(( 500 - ($(date +%s) - t1) )) | sed 's/^-.*/1/' )

– roaima
Feb 4 at 22:01





1




1





@roaima Sorry for being vague. I updated the question. I haven't got stuck anywhere. I just want to improve my code, as I believe it is not the efficient way.

– Googlebot
Feb 4 at 22:01





@roaima Sorry for being vague. I updated the question. I haven't got stuck anywhere. I just want to improve my code, as I believe it is not the efficient way.

– Googlebot
Feb 4 at 22:01













@DopeGhoti very good point indeed.

– Googlebot
Feb 4 at 22:02





@DopeGhoti very good point indeed.

– Googlebot
Feb 4 at 22:02










2 Answers
2






active

oldest

votes


















1














Here is how I would do it using bash special parameter SECONDS:



#!/bin/bash 

SECONDS=0
# script is here
sleep "$(( 500 > SECONDS ? 500 - SECONDS : 1 ))"


Normally SECONDS returns time (in seconds) since the script has started, but one can assign any value to (re)set the timer.






share|improve this answer




















  • 1





    Zeroing SECONDS doesn't hurt, and at least makes the initial value explicit, but since it tells the time since the script started you don't have to zero it. Unless the script does something else first, of course.

    – ilkkachu
    Feb 4 at 22:25


















4














What your script is, is non-portable (since you're using let and (( .. ))), confusing (since you're using both let and (( .. ))), lacking in documentation (there are no comments, and the variable names are non-descriptive), and marginally unsafe (since you haven't quoted the expansion of $t).



If you want a rewrite, here's mine:



#!/bin/sh

min_duration=500
t_start=$(date +%s)
# script is here
t_end=$(date +%s)
elapsed=$(( t_end - t_start ))

# sleep long enough to make sure 'min_duration' seconds has elapsed,
# but at least 1 second
sleep "$(( elapsed < min_duration ? min_duration - elapsed : 1 ))"





share|improve this answer




















  • 1





    Is there any practical difference between your : "$(( elapsed = t_end - t_start ))" and simply (( elapsed = t_end - t_start ))?

    – roaima
    Feb 4 at 22:11







  • 1





    @roaima The exit status when the calculation results in a zero. It matters when running under set -e. Personally, I think I would have used elapsed=$(( ... )). Also notice that he's writing for /bin/sh, not bash.

    – Kusalananda
    Feb 4 at 22:16












  • @roaima, I was just thinking about the portability point. At least dash and busybox don't support (( .. )). With Bash, I'd use (( .. )) since it looks less ugly to me. The exit status shouldn't matter (well, unless someone uses set -e, but let's not go there...)

    – ilkkachu
    Feb 4 at 22:18











  • @Kusalananda, argh, of course with elapsed=$((..))... Thanks.

    – ilkkachu
    Feb 4 at 22:19












  • @Kusalananda ah yes. Thankyou.

    – roaima
    Feb 5 at 0:18










Your Answer








StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f498680%2fdate-arithmetic-and-ternary-operator-in-one-line%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














Here is how I would do it using bash special parameter SECONDS:



#!/bin/bash 

SECONDS=0
# script is here
sleep "$(( 500 > SECONDS ? 500 - SECONDS : 1 ))"


Normally SECONDS returns time (in seconds) since the script has started, but one can assign any value to (re)set the timer.






share|improve this answer




















  • 1





    Zeroing SECONDS doesn't hurt, and at least makes the initial value explicit, but since it tells the time since the script started you don't have to zero it. Unless the script does something else first, of course.

    – ilkkachu
    Feb 4 at 22:25















1














Here is how I would do it using bash special parameter SECONDS:



#!/bin/bash 

SECONDS=0
# script is here
sleep "$(( 500 > SECONDS ? 500 - SECONDS : 1 ))"


Normally SECONDS returns time (in seconds) since the script has started, but one can assign any value to (re)set the timer.






share|improve this answer




















  • 1





    Zeroing SECONDS doesn't hurt, and at least makes the initial value explicit, but since it tells the time since the script started you don't have to zero it. Unless the script does something else first, of course.

    – ilkkachu
    Feb 4 at 22:25













1












1








1







Here is how I would do it using bash special parameter SECONDS:



#!/bin/bash 

SECONDS=0
# script is here
sleep "$(( 500 > SECONDS ? 500 - SECONDS : 1 ))"


Normally SECONDS returns time (in seconds) since the script has started, but one can assign any value to (re)set the timer.






share|improve this answer















Here is how I would do it using bash special parameter SECONDS:



#!/bin/bash 

SECONDS=0
# script is here
sleep "$(( 500 > SECONDS ? 500 - SECONDS : 1 ))"


Normally SECONDS returns time (in seconds) since the script has started, but one can assign any value to (re)set the timer.







share|improve this answer














share|improve this answer



share|improve this answer








edited Feb 4 at 22:21









Kusalananda

132k17253416




132k17253416










answered Feb 4 at 22:13









jimmijjimmij

31.9k874108




31.9k874108







  • 1





    Zeroing SECONDS doesn't hurt, and at least makes the initial value explicit, but since it tells the time since the script started you don't have to zero it. Unless the script does something else first, of course.

    – ilkkachu
    Feb 4 at 22:25












  • 1





    Zeroing SECONDS doesn't hurt, and at least makes the initial value explicit, but since it tells the time since the script started you don't have to zero it. Unless the script does something else first, of course.

    – ilkkachu
    Feb 4 at 22:25







1




1





Zeroing SECONDS doesn't hurt, and at least makes the initial value explicit, but since it tells the time since the script started you don't have to zero it. Unless the script does something else first, of course.

– ilkkachu
Feb 4 at 22:25





Zeroing SECONDS doesn't hurt, and at least makes the initial value explicit, but since it tells the time since the script started you don't have to zero it. Unless the script does something else first, of course.

– ilkkachu
Feb 4 at 22:25













4














What your script is, is non-portable (since you're using let and (( .. ))), confusing (since you're using both let and (( .. ))), lacking in documentation (there are no comments, and the variable names are non-descriptive), and marginally unsafe (since you haven't quoted the expansion of $t).



If you want a rewrite, here's mine:



#!/bin/sh

min_duration=500
t_start=$(date +%s)
# script is here
t_end=$(date +%s)
elapsed=$(( t_end - t_start ))

# sleep long enough to make sure 'min_duration' seconds has elapsed,
# but at least 1 second
sleep "$(( elapsed < min_duration ? min_duration - elapsed : 1 ))"





share|improve this answer




















  • 1





    Is there any practical difference between your : "$(( elapsed = t_end - t_start ))" and simply (( elapsed = t_end - t_start ))?

    – roaima
    Feb 4 at 22:11







  • 1





    @roaima The exit status when the calculation results in a zero. It matters when running under set -e. Personally, I think I would have used elapsed=$(( ... )). Also notice that he's writing for /bin/sh, not bash.

    – Kusalananda
    Feb 4 at 22:16












  • @roaima, I was just thinking about the portability point. At least dash and busybox don't support (( .. )). With Bash, I'd use (( .. )) since it looks less ugly to me. The exit status shouldn't matter (well, unless someone uses set -e, but let's not go there...)

    – ilkkachu
    Feb 4 at 22:18











  • @Kusalananda, argh, of course with elapsed=$((..))... Thanks.

    – ilkkachu
    Feb 4 at 22:19












  • @Kusalananda ah yes. Thankyou.

    – roaima
    Feb 5 at 0:18















4














What your script is, is non-portable (since you're using let and (( .. ))), confusing (since you're using both let and (( .. ))), lacking in documentation (there are no comments, and the variable names are non-descriptive), and marginally unsafe (since you haven't quoted the expansion of $t).



If you want a rewrite, here's mine:



#!/bin/sh

min_duration=500
t_start=$(date +%s)
# script is here
t_end=$(date +%s)
elapsed=$(( t_end - t_start ))

# sleep long enough to make sure 'min_duration' seconds has elapsed,
# but at least 1 second
sleep "$(( elapsed < min_duration ? min_duration - elapsed : 1 ))"





share|improve this answer




















  • 1





    Is there any practical difference between your : "$(( elapsed = t_end - t_start ))" and simply (( elapsed = t_end - t_start ))?

    – roaima
    Feb 4 at 22:11







  • 1





    @roaima The exit status when the calculation results in a zero. It matters when running under set -e. Personally, I think I would have used elapsed=$(( ... )). Also notice that he's writing for /bin/sh, not bash.

    – Kusalananda
    Feb 4 at 22:16












  • @roaima, I was just thinking about the portability point. At least dash and busybox don't support (( .. )). With Bash, I'd use (( .. )) since it looks less ugly to me. The exit status shouldn't matter (well, unless someone uses set -e, but let's not go there...)

    – ilkkachu
    Feb 4 at 22:18











  • @Kusalananda, argh, of course with elapsed=$((..))... Thanks.

    – ilkkachu
    Feb 4 at 22:19












  • @Kusalananda ah yes. Thankyou.

    – roaima
    Feb 5 at 0:18













4












4








4







What your script is, is non-portable (since you're using let and (( .. ))), confusing (since you're using both let and (( .. ))), lacking in documentation (there are no comments, and the variable names are non-descriptive), and marginally unsafe (since you haven't quoted the expansion of $t).



If you want a rewrite, here's mine:



#!/bin/sh

min_duration=500
t_start=$(date +%s)
# script is here
t_end=$(date +%s)
elapsed=$(( t_end - t_start ))

# sleep long enough to make sure 'min_duration' seconds has elapsed,
# but at least 1 second
sleep "$(( elapsed < min_duration ? min_duration - elapsed : 1 ))"





share|improve this answer















What your script is, is non-portable (since you're using let and (( .. ))), confusing (since you're using both let and (( .. ))), lacking in documentation (there are no comments, and the variable names are non-descriptive), and marginally unsafe (since you haven't quoted the expansion of $t).



If you want a rewrite, here's mine:



#!/bin/sh

min_duration=500
t_start=$(date +%s)
# script is here
t_end=$(date +%s)
elapsed=$(( t_end - t_start ))

# sleep long enough to make sure 'min_duration' seconds has elapsed,
# but at least 1 second
sleep "$(( elapsed < min_duration ? min_duration - elapsed : 1 ))"






share|improve this answer














share|improve this answer



share|improve this answer








edited Feb 4 at 22:19

























answered Feb 4 at 22:09









ilkkachuilkkachu

59.9k997169




59.9k997169







  • 1





    Is there any practical difference between your : "$(( elapsed = t_end - t_start ))" and simply (( elapsed = t_end - t_start ))?

    – roaima
    Feb 4 at 22:11







  • 1





    @roaima The exit status when the calculation results in a zero. It matters when running under set -e. Personally, I think I would have used elapsed=$(( ... )). Also notice that he's writing for /bin/sh, not bash.

    – Kusalananda
    Feb 4 at 22:16












  • @roaima, I was just thinking about the portability point. At least dash and busybox don't support (( .. )). With Bash, I'd use (( .. )) since it looks less ugly to me. The exit status shouldn't matter (well, unless someone uses set -e, but let's not go there...)

    – ilkkachu
    Feb 4 at 22:18











  • @Kusalananda, argh, of course with elapsed=$((..))... Thanks.

    – ilkkachu
    Feb 4 at 22:19












  • @Kusalananda ah yes. Thankyou.

    – roaima
    Feb 5 at 0:18












  • 1





    Is there any practical difference between your : "$(( elapsed = t_end - t_start ))" and simply (( elapsed = t_end - t_start ))?

    – roaima
    Feb 4 at 22:11







  • 1





    @roaima The exit status when the calculation results in a zero. It matters when running under set -e. Personally, I think I would have used elapsed=$(( ... )). Also notice that he's writing for /bin/sh, not bash.

    – Kusalananda
    Feb 4 at 22:16












  • @roaima, I was just thinking about the portability point. At least dash and busybox don't support (( .. )). With Bash, I'd use (( .. )) since it looks less ugly to me. The exit status shouldn't matter (well, unless someone uses set -e, but let's not go there...)

    – ilkkachu
    Feb 4 at 22:18











  • @Kusalananda, argh, of course with elapsed=$((..))... Thanks.

    – ilkkachu
    Feb 4 at 22:19












  • @Kusalananda ah yes. Thankyou.

    – roaima
    Feb 5 at 0:18







1




1





Is there any practical difference between your : "$(( elapsed = t_end - t_start ))" and simply (( elapsed = t_end - t_start ))?

– roaima
Feb 4 at 22:11






Is there any practical difference between your : "$(( elapsed = t_end - t_start ))" and simply (( elapsed = t_end - t_start ))?

– roaima
Feb 4 at 22:11





1




1





@roaima The exit status when the calculation results in a zero. It matters when running under set -e. Personally, I think I would have used elapsed=$(( ... )). Also notice that he's writing for /bin/sh, not bash.

– Kusalananda
Feb 4 at 22:16






@roaima The exit status when the calculation results in a zero. It matters when running under set -e. Personally, I think I would have used elapsed=$(( ... )). Also notice that he's writing for /bin/sh, not bash.

– Kusalananda
Feb 4 at 22:16














@roaima, I was just thinking about the portability point. At least dash and busybox don't support (( .. )). With Bash, I'd use (( .. )) since it looks less ugly to me. The exit status shouldn't matter (well, unless someone uses set -e, but let's not go there...)

– ilkkachu
Feb 4 at 22:18





@roaima, I was just thinking about the portability point. At least dash and busybox don't support (( .. )). With Bash, I'd use (( .. )) since it looks less ugly to me. The exit status shouldn't matter (well, unless someone uses set -e, but let's not go there...)

– ilkkachu
Feb 4 at 22:18













@Kusalananda, argh, of course with elapsed=$((..))... Thanks.

– ilkkachu
Feb 4 at 22:19






@Kusalananda, argh, of course with elapsed=$((..))... Thanks.

– ilkkachu
Feb 4 at 22:19














@Kusalananda ah yes. Thankyou.

– roaima
Feb 5 at 0:18





@Kusalananda ah yes. Thankyou.

– roaima
Feb 5 at 0:18

















draft saved

draft discarded
















































Thanks for contributing an answer to Unix & Linux Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f498680%2fdate-arithmetic-and-ternary-operator-in-one-line%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown






Popular posts from this blog

How to check contact read email or not when send email to Individual?

Bahrain

Postfix configuration issue with fips on centos 7; mailgun relay