summaryrefslogtreecommitdiff
path: root/tests/test-echo.sh
blob: f4c62d14e733a741a9b165a6d1b3882e3d056078 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#! /bin/sh

# func_exit STATUS
# exit with status
func_exit ()
{
  (exit $1); exit $1
}

# func_fatal_error message
# outputs to stderr a fatal error message, and terminates the program.
func_fatal_error ()
{
  echo "test-echo.sh: *** $1" 1>&2
  echo "test-echo.sh: *** Stop." 1>&2
  func_exit 1
}

# 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 (except that
# BSD echo interprets '-n' as an option, which is also not desirable).
# Nowadays the problem occurs in 4 situations:
# - in bash, when the shell option xpg_echo is set (bash >= 2.04)
#            or when it was built with --enable-usg-echo-default (bash >= 2.0)
#            or when it was built with DEFAULT_ECHO_TO_USG (bash < 2.0),
# - 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 >= 2.04: unset the shell option xpg_echo.
# - for bash >= 2.0: define echo to a function that uses the printf built-in.
# - for bash < 2.0: define echo to a function that uses cat of a here document.
# - for zsh: turn sh-emulation on.
# - for ksh: alias echo to 'print -r'.
# - for ksh: alias echo to a function that uses cat of a here document.
# - for Solaris /bin/sh and OSF/1 /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 >= 2.04: 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 bash >= 2.0: define echo to a function that uses the printf built-in.
# For bash < 2.0: define echo to a function that uses cat of a here document.
# (There is no win in using 'printf' over 'cat' if it is not a shell built-in.)
if test -z "$have_echo" \
   && test -n "$BASH_VERSION"; then \
  if type printf 2>/dev/null | grep / > /dev/null; then
    # 'printf' is not a shell built-in.
echo ()
{
cat <<EOF
$*
EOF
}
  else
    # 'printf' is a shell built-in.
echo ()
{
  printf '%s\n' "$*"
}
  fi
  if echo '\t' | grep t > /dev/null; then
    have_echo=yes
  fi
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 'print -r'.
if test -z "$have_echo" \
   && (type print) >/dev/null 2>&1; then
  # A 'print' command exists.
  if type print 2>/dev/null | grep / > /dev/null; then
    :
  else
    # 'print' is a shell built-in.
    if (print -r '\told' | grep told > /dev/null) 2>/dev/null; then
      # 'print' is the ksh shell built-in.
      alias echo='print -r'
    fi
  fi
fi
if test -z "$have_echo" \
   && echo '\t' | grep t > /dev/null; then
  have_echo=yes
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 starts after the 'alias'
# command.
if test -z "$have_echo"; then
bsd_echo ()
{
cat <<EOF
$*
EOF
}
alias echo=bsd_echo 2>/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

# This command determines the exit code.
echo '\t' | grep t > /dev/null