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
    3 hours ago








  • 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
    3 hours ago






  • 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
    3 hours ago








  • 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
    3 hours ago











  • @DopeGhoti very good point indeed.

    – Googlebot
    3 hours ago
















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
    3 hours ago








  • 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
    3 hours ago






  • 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
    3 hours ago








  • 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
    3 hours ago











  • @DopeGhoti very good point indeed.

    – Googlebot
    3 hours ago














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 3 hours ago









jimmij

31.2k871106




31.2k871106










asked 3 hours ago









GooglebotGooglebot

487621




487621













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

    – roaima
    3 hours ago








  • 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
    3 hours ago






  • 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
    3 hours ago








  • 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
    3 hours ago











  • @DopeGhoti very good point indeed.

    – Googlebot
    3 hours ago



















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

    – roaima
    3 hours ago








  • 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
    3 hours ago






  • 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
    3 hours ago








  • 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
    3 hours ago











  • @DopeGhoti very good point indeed.

    – Googlebot
    3 hours ago

















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

– roaima
3 hours ago







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

– roaima
3 hours ago






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
3 hours ago





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
3 hours ago




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
3 hours ago







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
3 hours ago






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
3 hours ago





@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
3 hours ago













@DopeGhoti very good point indeed.

– Googlebot
3 hours ago





@DopeGhoti very good point indeed.

– Googlebot
3 hours ago










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


























  • 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
    3 hours ago



















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
    3 hours ago








  • 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
    3 hours ago













  • @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
    3 hours ago











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

    – ilkkachu
    3 hours ago













  • @Kusalananda ah yes. Thankyou.

    – roaima
    1 hour ago











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


























  • 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
    3 hours ago
















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


























  • 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
    3 hours ago














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 3 hours ago









Kusalananda

128k16241398




128k16241398










answered 3 hours ago









jimmijjimmij

31.2k871106




31.2k871106













  • 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
    3 hours ago



















  • 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
    3 hours ago

















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
3 hours ago





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
3 hours ago













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
    3 hours ago








  • 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
    3 hours ago













  • @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
    3 hours ago











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

    – ilkkachu
    3 hours ago













  • @Kusalananda ah yes. Thankyou.

    – roaima
    1 hour ago
















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
    3 hours ago








  • 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
    3 hours ago













  • @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
    3 hours ago











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

    – ilkkachu
    3 hours ago













  • @Kusalananda ah yes. Thankyou.

    – roaima
    1 hour ago














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 3 hours ago

























answered 3 hours ago









ilkkachuilkkachu

57.9k888163




57.9k888163








  • 1





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

    – roaima
    3 hours ago








  • 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
    3 hours ago













  • @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
    3 hours ago











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

    – ilkkachu
    3 hours ago













  • @Kusalananda ah yes. Thankyou.

    – roaima
    1 hour ago














  • 1





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

    – roaima
    3 hours ago








  • 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
    3 hours ago













  • @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
    3 hours ago











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

    – ilkkachu
    3 hours ago













  • @Kusalananda ah yes. Thankyou.

    – roaima
    1 hour ago








1




1





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

– roaima
3 hours ago







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

– roaima
3 hours ago






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
3 hours ago







@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
3 hours ago















@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
3 hours ago





@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
3 hours ago













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

– ilkkachu
3 hours ago







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

– ilkkachu
3 hours ago















@Kusalananda ah yes. Thankyou.

– roaima
1 hour ago





@Kusalananda ah yes. Thankyou.

– roaima
1 hour ago


















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

Terni

A new problem with tex4ht and tikz

Sun Ra