1

I want to set a bash variable to the output of a command and ensure it is all lowercase. I want to keep my code as clean as possible and not pipe output anywhere.

This is what I had before:

host=$(hostname -s | tr '[:upper:]' '[:lower:]')

Instead I am now using two definitions (being slightly shorter):

host=$(hostname -s); host=${host,,}

but I'm wondering if it's possible to do it in just one definition for host without piping to tr (or anything else). Can the second line be combined any further?

Edit: This is exactly why I should copy/paste my code. I did in fact have '[:upper:]' and '[:lower:]' in my script but typed it incorrectly.

4
  • 1
    I think, it isn't possible. But whats bad bout using 2 definitions? Commented May 16, 2019 at 5:51
  • @Wiimm it's really a matter of keeping a single definition to improve readability. I think the second, shorter version is just about the same amount of readable so I'm not really seeing an advantage. I thought if I could have it happening in one fell swoop, it'd make it easier. I suppose I should be relying on good comments, anyway. Commented May 16, 2019 at 17:01
  • 2
    host=$(hostname -s | tr [:upper:] [:lower:]) is bad because the tr command will get messed up if it is run in a directory that contains a file whose name is a single character :, e, l, o, p, r, u, or w. host=$(hostname -s | tr '[:upper:]' '[:lower:]') is good. See the "Ranges" section in glob - Greg's Wiki for details of why the quotes are necessary. Commented May 16, 2019 at 18:37
  • I'd argue that trying to combine things further is actively a bad idea for error-handling purposes. With two commands, the first one has a distinct exit status that can be acted on; combine the second always-successful command in and you can lose that -- much akin to how local result=$(someCommand) always reports true because local succeeds, even if someCommand fails. Commented May 16, 2019 at 21:16

1 Answer 1

1

If you have Bash 4.0 (released in 2009) you can declare host so the conversion to lowercase is done automatically on assignment:

declare -l host
host=$(hostname -s)

If the code is in a function then it's best to localize variables whenever possible, so

local -l host
host=$(hostname -s)

is only very slightly longer than code that doesn't lowercase the hostname.

It is possible to do the declaration and assignment at the same time

declare -l host=$(hostname -s)  # BAD CODE

but Shellcheck will correctly complain that this masks the exit status of hostname, so you can't detect or handle an error.

In this particular case the declaration and assignment can be safely done at the same time if you use the Bash built-in HOSTNAME variable instead of the external hostname command:

declare -l host=${HOSTNAME%%.*}
Sign up to request clarification or add additional context in comments.

2 Comments

Note that declare implies local by default.
This is fantastic @pjh, thank you! This is exactly what I was looking for. You make a good point about not being able to properly handle any errors, however so I think I'll include one line for all those variables that need to stay lowercase.

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.