From 3ce27eb05077881b96ea419a24485199e31951b1 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 23 Jun 2007 02:02:46 +0000 Subject: [PATCH] Ensure a POSIX:2001 compliant 'echo' command. --- ChangeLog | 6 ++++ gnulib-tool | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ae94a0b999..9fdea13428 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2007-06-22 Bruno Haible + + * gnulib-tool (echo): Ensure the echo primitive does not interpret + backslashes. + * tests/test-echo.sh: New file. + 2007-06-22 Ralf Wildenhues * gnulib-tool (func_add_or_update, func_create_testdir): Do not diff --git a/gnulib-tool b/gnulib-tool index 5a13973748..559aa7ca98 100755 --- a/gnulib-tool +++ b/gnulib-tool @@ -22,7 +22,7 @@ progname=$0 package=gnulib -cvsdatestamp='$Date: 2007-06-22 18:16:40 $' +cvsdatestamp='$Date: 2007-06-23 02:02:46 $' last_checkin_date=`echo "$cvsdatestamp" | sed -e 's,^\$[D]ate: ,,'` version=`echo "$last_checkin_date" | sed -e 's/ .*$//' -e 's,/,-,g'` nl=' @@ -410,6 +410,103 @@ func_ln_if_changed () fi } +# Ensure an 'echo' command that does not interpret backslashes. +# Test cases: +# echo '\n' | wc -l prints 1 when OK, 2 when KO +# echo '\t' | grep t > /dev/null has return code 0 when OK, 1 when KO +# This problem is a weird heritage from SVR4. BSD got it right. +# Nowadays the problem occurs in 4 situations: +# - in bash, when the shell option xpg_echo is set, +# - in zsh, when sh-emulation is not set, +# - in ksh (e.g. AIX /bin/sh and Solaris /usr/xpg4/bin/sh are ksh instances, +# and HP-UX /bin/sh and IRIX /bin/sh behave similarly), +# - in Solaris /bin/sh and OSF/1 /bin/sh. +# We try the following workarounds: +# - for all: respawn using $CONFIG_SHELL if that is set and works. +# - for bash: unset the shell option xpg_echo. +# - for zsh: turn sh-emulation on. +# - for ksh: alias echo to a function that uses cat of a here document. +# - for Solaris /bin/sh: respawn using /bin/ksh and rely on the ksh workaround. +# - otherwise: respawn using /bin/sh and rely on the workarounds. +# When respawning, we pass --no-reexec as first argument, so as to avoid +# turning this script into a fork bomb in unlucky situations. +have_echo= +if echo '\t' | grep t > /dev/null; then + have_echo=yes # Lucky! +fi +# Try the workarounds. +# Respawn using $CONFIG_SHELL if that is set and works. +if test -z "$have_echo" \ + && test "X$1" != "X--no-reexec" \ + && test -n "$CONFIG_SHELL" \ + && test -f "$CONFIG_SHELL" \ + && $CONFIG_SHELL -c 'echo '\t' | grep t > /dev/null'; then + exec $CONFIG_SHELL "$0" --no-reexec "$@" + exit 127 +fi +# For bash: unset the shell option xpg_echo. +if test -z "$have_echo" \ + && test -n "$BASH_VERSION" \ + && (shopt -o xpg_echo; echo '\t' | grep t > /dev/null) 2>/dev/null; then + shopt -o xpg_echo + have_echo=yes +fi +# For zsh: turn sh-emulation on. +if test -z "$have_echo" \ + && test -n "$ZSH_VERSION" \ + && (emulate sh) >/dev/null 2>&1; then + emulate sh +fi +# For ksh: alias echo to a function that uses cat of a here document. +# The ksh manual page says: +# "Aliasing is performed when scripts are read, not while they are executed. +# Therefore, for an alias to take effect, the alias definition command has +# to be executed before the command which references the alias is read." +# Because of this, we have to play strange tricks with have_echo, to ensure +# that the top-level statement containing the test start after the 'alias' +# command. +if test -z "$have_echo"; then +bsd_echo () +{ +cat </dev/null +fi +if test -z "$have_echo" \ + && echo '\t' | grep t > /dev/null; then + have_echo=yes +fi +if test -z "$have_echo"; then + unalias echo 2>/dev/null +fi +# For Solaris /bin/sh and OSF/1 /bin/sh: respawn using /bin/ksh. +if test -z "$have_echo" \ + && test "X$1" != "X--no-reexec" \ + && test -f /bin/ksh; then + exec /bin/ksh "$0" --no-reexec "$@" + exit 127 +fi +# Otherwise: respawn using /bin/sh. +if test -z "$have_echo" \ + && test "X$1" != "X--no-reexec" \ + && test -f /bin/sh; then + exec /bin/sh "$0" --no-reexec "$@" + exit 127 +fi +if test -z "$have_echo"; then + func_fatal_error "Shell does not support 'echo' correctly. Please install GNU bash and set the environment variable CONFIG_SHELL to point to it." +fi +if echo '\t' | grep t > /dev/null; then + : # Works fine now. +else + func_fatal_error "Shell does not support 'echo' correctly. Workaround does not work. Please report this as a bug to bug-gnulib@gnu.org." +fi +if test "X$1" = "X--no-reexec"; then + shift +fi + # Command-line option processing. # Removes the OPTIONS from the arguments. Sets the variables: # - mode list or import or create-testdir or create-megatestdir -- 2.30.2