Common Bash programming errors (end)

Original author: Greg Wooledge
  • Transfer
The end of the translation of Bash Pitfalls . The previous parts are available on the Shells blog ( part 1 , part 2 ) and on my blog .

22. echo "Hello World!"


The problem is that in the Bash interactive shell this command will throw an error:
bash:! ": event not found

This is because, at default settings, Bash performs csh-style command history substitution using an exclamation mark. There is no such problem in scripts, only in an interactive shell.

The obvious solution does not work here:
$ echo "hi \!"
hi \!


You can enclose this string in single quotes:
echo 'Hello World!'

But the most suitable solution here is to temporarily turn off the parameter histexpand. This can be done with the command set +Hor set +o histexpand:
set + H
echo "Hello World!"

Why then not always use single quotes? Imagine that you want information about mp3 files:
mp3info -t "Don't Let It Show" ...
mp3info -t "Ah! Leah!" ...

Single quotes are not suitable here, since the song names contain apostrophes in the names, and the use of double quotes will lead to a problem with the substitution of the history of commands (and if double quotes were also contained in the file names, it would be generally a damn thing). Since I personally (Greg Wooledge, author of the text) never use command history substitution, I just put the command set +Hin my .bashrc. But this is a matter of habit and everyone decides for himself.

23. for arg in $ *


In Bash, just like in other shells of the Bourne shell family, there is a special syntax for working with positional parameters in turn, but $*also $@not quite what you need: after parameter substitution, they become a list of words passed in arguments, rather than a list of options individually.

Here is the correct syntax:
for arg in "$ @"

Or simply:
for arg

for argmatches for arg in "$@". A variable enclosed in double quotes "$@"is a special street magic, thanks to which every command line argument is enclosed in double quotes, so that it looks like a separate word. In other words, "$@"converted to a list "$1" "$2" "$3", etc. This trick will work in most cases.

Consider an example:
#! / bin / bash
# wrong
for x in $ *; do
echo "parameter: '$ x'"
done

This code will print:
$ ./myscript 'arg 1' arg2 arg3
parameter: 'arg'
parameter: '1'
parameter: 'arg2'
parameter: 'arg3'

Here's how it should look:
#! / bin / bash
# right!
for x in "$ @"; do
    echo "parameter: '$ x'"
done


$ ./myscript 'arg 1' arg2 arg3
parameter: 'arg 1'
parameter: 'arg2'
parameter: 'arg3'

24. function foo ()


In some shells this works, but not in all. Never combine a keyword functionwith brackets () when defining a function.

Some versions of bash allow you to use both function, and (), at the same time , but you cannot do this in any other shell. Some interpreters, however, will perceive function foo, but for maximum compatibility it is better to use:
foo () {
 ...
}

25. echo "~"


A tilde expansion only happens when the ~ character is not surrounded by quotation marks. This example echowill output ~to stdout, instead of listing the user home directory.

Escaping variables with paths that must be expressed relative to the home directory should be done using $HOMEinstead ~.
"~ / dir with spaces" # "~ / dir with spaces"
~ "/ dir with spaces" # "~ / dir with spaces"
~ / "dir with spaces" # "/ home / my photos / dir with spaces"
"$ HOME / dir with spaces" # "/ home / my photos / dir with spaces"

26. local varname = $ (command)


By defining a local variable in a function, it localitself works as a command. Sometimes this may inexplicably interact with the rest of the string. For example, if in the next command you want to receive the return code ($?) Of the substituted command, you will not receive it: the return code of the local command overrides it.

Therefore, these commands are best separated:
local varname
varname = $ (command)
rc = $?

Also popular now: