Live data from Hacker News

Bash patterns I use weekly

will-keleher.com

21–30 of 115 posts

Re: Bash patterns I use weekly

#21

This thread seems like a good place to ask this: When you're running a script, what is the expected behaviour if you just run it with no arguments? I think it shouldn't make any changes to your system, and it should print out a help message with common options. Is there anything else you expect a script to do? Do you prefer a script that has a set of default assumptions about how it's going to work? If you need to mo…

What is your intended audience? It is you? A batch job or called by another program? Or a person that may or not be able to read bash and will call it manually?

A good and descriptive name comes first, then the action and the people that may have to run it are next.

Re: Bash patterns I use weekly

#22
post #16
post #7

Earlier quoted context omitted.

Even more correct would be to use an array: stuff=("foo foo" "bar" "baz") for route in "${stuff[@]}"; do curl localhost:8080/"$route" done

"${stuff[@]}" would be turning it back into "foo bar baz" though, right? I think if you were using arrays for this, it'd be something like: stuff=("foo" "bar" "baz"); array_length=${#stuff[@]}; for i in $(seq 0 $array_length); do curl localhost:8080/${stuff[i]} done I'm betting even that isn't right: as soon as bash arrays are a thing, I reach for a different language. [edit]: trying to get formatting correct

"${stuff[@]}" expands into the elements of the array, with each one quoted - so even that first "foo foo" element with a space will be handled correctly. That is how I would write the loop as well, in general.

However, your technique also works, with some tweaks:

* The loop goes one index too far, and can be fixed with seq 0 $(( array_length - 1 ))

* There should be quotes around ${stuff[i]} in case it has spaces

Re: Bash patterns I use weekly

#23
post #16
post #7

Earlier quoted context omitted.

Even more correct would be to use an array: stuff=("foo foo" "bar" "baz") for route in "${stuff[@]}"; do curl localhost:8080/"$route" done

"${stuff[@]}" would be turning it back into "foo bar baz" though, right? I think if you were using arrays for this, it'd be something like: stuff=("foo" "bar" "baz"); array_length=${#stuff[@]}; for i in $(seq 0 $array_length); do curl localhost:8080/${stuff[i]} done I'm betting even that isn't right: as soon as bash arrays are a thing, I reach for a different language. [edit]: trying to get formatting correct

[deleted]

Re: Bash patterns I use weekly

#24
I have something like this in my bashrc:

   preexec ()
   {
       # shellcheck disable=2034
       _CMD_START="$(date +%s)"
   }

   trap 'preexec; trap - DEBUG' DEBUG

   PROMPT_COMMAND="_CMD_STOP=\$(date +%s)
       let _CMD_ELAPSED=_CMD_STOP-_CMD_START

       if [ \$_CMD_ELAPSED -gt 5 ]; then
           _TIME_STR=\" (\${_CMD_ELAPSED}s)\"
       else
           _TIME_STR=''
       fi; "

    PS1="\n\u@\h \w\$_TIME_STR\n\\$ "

    PROMPT_COMMAND+="trap 'preexec; trap - DEBUG' DEBUG"
Whenever a command takes more than 5 s it tells me exactly how long at the next prompt.

I didn't know about `$SECONDS` so I'm going to change it to use that.

Re: Bash patterns I use weekly

#25

I have something like this in my bashrc: preexec () { # shellcheck disable=2034 _CMD_START="$(date +%s)" } trap 'preexec; trap - DEBUG' DEBUG PROMPT_COMMAND="_CMD_STOP=\$(date +%s) let _CMD_ELAPSED=_CMD_STOP-_CMD_START if [ \$_CMD_ELAPSED -gt 5 ]; then _TIME_STR=\" (\${_CMD_ELAPSED}s)\" else _TIME_STR='' fi; " PS1="\n\u@\h \w\$_TIME_STR\n\\$ " PROMPT_COMMAND+="trap 'preexec; trap - DEBUG' DEBUG" Whenever a command ta…

FWIW that is supported by many zsh themes like pure, p9k, p10k, ... (and often enabled by default).

Also:

    REPORTTIME
    If nonnegative, commands whose combined user and system execution times (measured in seconds) are greater than this value have timing statistics printed for them.
which is slightly different but generally useful, and built-in.

Re: Bash patterns I use weekly

#26

> git bisect is the "real" way to do this, but it's not something I've ever needed uh, yeah, you did need it, that's why you came up with "2. Track down a commit when a command started failing". Seriously though, git bisect is really useful to track down that bug in O(log n) rather than O(n).

Also provides super useful commands like skipping commits because some of your colleagues are assholes and commit non-working code.

Re: Bash patterns I use weekly

#27
Installing GNU stuff with the 'g' prefix (gsed instead of sed) means having to remember to include the 'g' when you're on a Mac and leave it off when you're on Linux, or use aliases, or some other confusing and inconvenient thing, and then if you're writing a script meant for multi-platform use, it still won't work. I find it's a much better idea to install the entire GNU suite without the 'g' prefix and use PATH to control which is used. I use MacPorts to do this (/opt/local/libexec/gnubin), and even Homebrew finally supports this, although it does it in a stupid way that requires adding a PATH element for each individual GNU utility (e.g. /usr/local/opt/gnu-sed/libexec/gnubin).

Re: Bash patterns I use weekly

#28

This thread seems like a good place to ask this: When you're running a script, what is the expected behaviour if you just run it with no arguments? I think it shouldn't make any changes to your system, and it should print out a help message with common options. Is there anything else you expect a script to do? Do you prefer a script that has a set of default assumptions about how it's going to work? If you need to mo…

A script is just another command, the only difference in this case is that you wrote it and not someone else. If its purpose is to make changes, and it's obvious what changes it should make without any arguments, I'd say it can do so without further ado. poweroff doesn't ask me what I want to do - I already told it by executing it - and that's a pretty drastic change.

Commands that halt halfway through and expect user confirmation should definitely have an option to skip that behavior. I want to be able to use anything in a script of my own.

Re: Bash patterns I use weekly

#29

This thread seems like a good place to ask this: When you're running a script, what is the expected behaviour if you just run it with no arguments? I think it shouldn't make any changes to your system, and it should print out a help message with common options. Is there anything else you expect a script to do? Do you prefer a script that has a set of default assumptions about how it's going to work? If you need to mo…

> When you're running a script, what is the expected behaviour if you just run it with no arguments? I think it shouldn't make any changes to your system, and it should print out a help message with common options. Is there anything else you expect a script to do?

Most scripts I use, custom-made or not, should be clear enough in their name for what they do. If in doubt, always call with --help/-h. But for example, it doesn't make sense that something like 'update-ca-certificates' requires arguments to execute: it's clear from the name it's going to change something.

> Do you prefer a script that has a set of default assumptions about how it's going to work? If you need to modify that, you pass in parameters.

It depends. If there's a "default" way to call the script, then yes. For example, in the 'update-ca-certificates' example, just use some defaults so I don't need to read more documentation about where the certificates are stored or how to do things.

> Do you expect that a script will lay out the changes it's about to make, then ask for confirmation? Or should it just get out of your way and do what it was written to do?

I don't care too much, but give me options to switch. If it does everything without asking, give me a "--dry-run" option or something that lets me check before doing anything. On the other hand, if it's asking a lot, let me specify "--yes" as apt does so that it doesn't ask me anything in automated installs or things like that.

Re: Bash patterns I use weekly

#30
post #16

Earlier quoted context omitted.

"${stuff[@]}" would be turning it back into "foo bar baz" though, right? I think if you were using arrays for this, it'd be something like: stuff=("foo" "bar" "baz"); array_length=${#stuff[@]}; for i in $(seq 0 $array_length); do curl localhost:8080/${stuff[i]} done I'm betting even that isn't right: as soon as bash arrays are a thing, I reach for a different language. [edit]: trying to get formatting correct

"${stuff[@]}" expands into the elements of the array, with each one quoted - so even that first "foo foo" element with a space will be handled correctly. That is how I would write the loop as well, in general. However, your technique also works, with some tweaks: * The loop goes one index too far, and can be fixed with seq 0 $(( array_length - 1 )) * There should be quotes around ${stuff[i]} in case it has spaces

Oh, that's way better for sure! Thanks for the explanation
Post reply on HN