Date, arithmetic, and ternary operator in one line












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
    yesterday








  • 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
    yesterday






  • 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
    yesterday








  • 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
    yesterday











  • @DopeGhoti very good point indeed.

    – Googlebot
    yesterday
















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
    yesterday








  • 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
    yesterday






  • 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
    yesterday








  • 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
    yesterday











  • @DopeGhoti very good point indeed.

    – Googlebot
    yesterday














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 yesterday









jimmij

31.2k871106




31.2k871106










asked yesterday









GooglebotGooglebot

487621




487621













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

    – roaima
    yesterday








  • 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
    yesterday






  • 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
    yesterday








  • 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
    yesterday











  • @DopeGhoti very good point indeed.

    – Googlebot
    yesterday



















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

    – roaima
    yesterday








  • 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
    yesterday






  • 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
    yesterday








  • 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
    yesterday











  • @DopeGhoti very good point indeed.

    – Googlebot
    yesterday

















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

– roaima
yesterday







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

– roaima
yesterday






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
yesterday





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
yesterday




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
yesterday







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
yesterday






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
yesterday





@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
yesterday













@DopeGhoti very good point indeed.

– Googlebot
yesterday





@DopeGhoti very good point indeed.

– Googlebot
yesterday










2 Answers
2






active

oldest

votes


















2














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
    yesterday



















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
    yesterday








  • 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
    yesterday













  • @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
    yesterday











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

    – ilkkachu
    yesterday













  • @Kusalananda ah yes. Thankyou.

    – roaima
    yesterday











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









2














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
    yesterday
















2














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
    yesterday














2












2








2







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 yesterday









Kusalananda

128k16241398




128k16241398










answered yesterday









jimmijjimmij

31.2k871106




31.2k871106








  • 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
    yesterday














  • 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
    yesterday








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
yesterday





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
yesterday













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
    yesterday








  • 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
    yesterday













  • @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
    yesterday











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

    – ilkkachu
    yesterday













  • @Kusalananda ah yes. Thankyou.

    – roaima
    yesterday
















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
    yesterday








  • 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
    yesterday













  • @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
    yesterday











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

    – ilkkachu
    yesterday













  • @Kusalananda ah yes. Thankyou.

    – roaima
    yesterday














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 yesterday

























answered yesterday









ilkkachuilkkachu

58.1k889164




58.1k889164








  • 1





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

    – roaima
    yesterday








  • 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
    yesterday













  • @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
    yesterday











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

    – ilkkachu
    yesterday













  • @Kusalananda ah yes. Thankyou.

    – roaima
    yesterday














  • 1





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

    – roaima
    yesterday








  • 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
    yesterday













  • @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
    yesterday











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

    – ilkkachu
    yesterday













  • @Kusalananda ah yes. Thankyou.

    – roaima
    yesterday








1




1





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

– roaima
yesterday







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

– roaima
yesterday






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
yesterday







@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
yesterday















@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
yesterday





@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
yesterday













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

– ilkkachu
yesterday







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

– ilkkachu
yesterday















@Kusalananda ah yes. Thankyou.

– roaima
yesterday





@Kusalananda ah yes. Thankyou.

– roaima
yesterday


















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

If I really need a card on my start hand, how many mulligans make sense? [duplicate]

Alcedinidae

Can an atomic nucleus contain both particles and antiparticles? [duplicate]