Showing posts with label bash. Show all posts
Showing posts with label bash. Show all posts

BASH’s compat31 option

Several of my bash scripts failed when I migrated from Debian to Gentoo almost one year ago for the different ways bash interpretes commands like this: [[ "$x" =~ '^[0-9]$' ]]. This command succeeded in Debian when $x is a single digit, but failed in Gentoo. I had to remove the single quotes surround the regular expression to make it work in Gentoo.

Today I finally found the reason: I was using bash 3.1 in Debian and 3.2 in Gentoo. Bash 3.2 by default mandates that regular expressions not be surrounded by quotes; however, the behavior can be modified using shopt -s compat31.

How BASH Changes Terminal Window Title

In many distributions bash automatically changes the terminal title. I thought it was hardcoded in bash, but it turns out to be not. It is usually implemented with PROMPT_COMMAND.

Environment variable $PROMPT_COMMAND defines the command to be automatically executed before displaying the primary prompt (i.e. $PS1). It is set by a script that is sourced by interative instances of bash. In Gentoo it is in /etc/bash/bashrc:
case ${TERM} in
    xterm*|rxvt*|Eterm|aterm|kterm|gnome*|interix)
        PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:${PWD/$HOME/~}\007"'
        ;;
    screen)
        PROMPT_COMMAND='echo -ne "\033_${USER}@${HOSTNAME%%.*}:${PWD/$HOME/~}\033\\"'
        ;;
esac

In fact, the first version above also works with newer versions of screen.

BASH’s ‘read’ built-in supports '\0' as delimiter

I thought it was impossible to use '\0' as a delimiter in bash, but noticed yesterday that Gentoo’s ebuild.sh had pipelines like this:
find ..... -print0 |
while read -r -d $'\0' x; do
# Do something with file $x
done

This makes it possible to handle any strange filenames correctly, even if the filename contains newline ('\n') or carriage return ('\r') characters. (Some other commands, including sort and xargs, have options to make null character the delimiter based on the same reason.)

Because BASH internally uses C-style strings, in which '\0' is the terminator, read -d $'\0' is essentially equivalent to read -d ''. This is why I believed read did not accept null-delimited strings. However, it turns out that BASH actually handles this correctly.

I checked BASH’s souce code and found the delimiter was simply determined by delim = *list_optarg; (bash-3.2/builtins/read.def, line 296) where list_optarg points to the argument following -d. Therefore, it makes no difference to the value of delim whether $'\0' or '' is used.