Archive

Uncategorized

Word splitting somehow includes trimming, e.g. removing leading and trailing whitespace.

$ X="        
bim bam   bomm    "
$ echo A${X}A
A bim bam bomm A

This is not exactly trimming, though.

  • If there is whitespace it is not replaced by nothing but by a single space.
  • Whitespace in the middle of the string is replaced too.

How do we trim? The answer can be found on stackoverflow.com

For other languages people quickly go over it with some answer like trim(), chasing after whatever distracting real world problems instead. For bash we explore possible solutions at rest. Or, we would if they let us do so.

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Spam was supposedly not the problem.

Advertisements

http://mywiki.wooledge.org/BashPitfalls highlights the “broken legacy misfeature” word splitting.

Before a bash command is executed the arguments are processed. After most of other processing is done, any argument containing whitespace is split into separate arguments, unless the whitespace is somehow protected. This is the word splitting feature and it is one big source of trouble.

Users tend to believe that in the line

cmd $A

there is a command with one argument. But in truth the number of arguments cannot be seen unless you know how the value of A was defined.

This is somehow unnecessary. Tcl is similar to bash as is does not really has types, uses polish notation, and variable are referenced by putting a $ in front of the variable name. But when you refer a variable in tcl you always get one value. If the value is a list and if you want pass its entries as separate arguments you have to split it up explicitly.

All together tcl solves the distinctions of whitespace that separates items and whitespace that belongs to items pretty well. The tcl way of solving it cannot be added to bash as it uses curly brackets that are, as any other brackets, already loaded with semantics in bash. Nonetheless, its strange that the prevailing scripting language affords to make people stumble on this issue.

From http://xonsh.org/faq.html

Even though I have been using BASH for well over a decade, I am not even sure I know how to add two numbers together in it or consistently create an array.

And instead of whining they come up with a serious alternative. Its a python-shell that attempts to mimic some important aspects of linux-shells. You can install it via pip.

Container types like mappings are mainly for people who are weak and tent to lose track. We avoid structured types because they make things unnecessarily simple. On the other hand bashs associative arrays come with a special syntax, so there is no danger people understand your code easily.

Lets create an associative array.

declare -A A=([a]=3 [b]=6 [c]=14) 

How do we get all keys a, b, c from A?

$A[{@!}]
$!A{[@]}
${A[@]!}
${!A[@]}
${A![@]}
${@A[!]}
${!A[]@}

Hints:

  • As discussed earlier, to get all values we write ${A[@]}.
  • With ${!X} we refer the value of the variable with name $X

In an earlier post we discussed processing the output of the find command, e.g. a list of paths. Since a path may contain spaces using just whitespace as separator between the list entires wont always work.

A common solution is the one given here. The bash variable IFS (“Internal Field Separator”) is set to newline and then set back to the original value in order to avoid trouble that may arise from changing this important parameter.

#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for f in *
do
  echo "$f"
done
IFS=$SAVEIFS

Why is the output of echo is used for setting the IFS to newline instead of a plain "\n"? I do not know but I am afraid of the reasons there might be for this. Anyway, setting and setting back that variable is somehow crooked. What if the command within the for-body relied on the preset value of IFS?

Dealing with containers such as lists or arrays you may want to code a condition like ‘does the array A contains an element (equal to) e’.
How to do this in bash? There are vivid discussions about this issue on relevant sites. As stated by tokland at superuser.com:

It’s an old question.

A frequently proposed solution is this.

A=(4 12 35 43)
e=12
if [[ ${A[@]} =~ $e ]] ; then
    echo "e=$e is in A"
fi

It works fine under certain conditions.

e=5 is in A

If you actually want to rely on the outcome you should iterate over the array, see check-if-an-array-contains-a-value. This comes quite handy and you can even save some lines by using ;.