From 3172b740fa379cedeb76073d08988f853d2b5b93 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 6 Aug 2024 10:13:05 -0700 Subject: [PATCH] =?utf8?q?Improve=20coverage=20of=20=E2=80=98echo=E2=80=99?= =?utf8?q?=20in=20manual?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit In manual, prefer AS_ECHO or printf instead of echo, when that might make a difference. Don’t use ‘date >timestamp’, to avoid spurious diffs. * doc/autoconf.texi (Notices): No need to worry any more about RCS or CVS being used to maintain Autoconf. (Preset Output Variables): Say that ECHO_N etc. are obsolete. (Automatic Remaking): Remove obsolescent mention of CVS. (AS_ECHO): Mention that AS_ECHO expands to something involving “'”, and how to work around this (rare) issue. (Shell Substitutions, Slashes, Limitations of Builtins): Omit no-longer-relevant discussion about ancient shell bugs that involved a lot of ‘echo’s that would otherwise need to be replaced. (Limitations of Builtins): Don’t mention ‘echo "x$word"’ trick, as it doesn’t resist backslashes. Just use printf. Expand on discussion of ‘echo’ options. Say that even modernish shells (e.g., ksh93 on OmniOS) sometimes screw up with here-documents. (Making testsuite Scripts): Simplify $(srcdir)/package.m4 rule by using printf instead of echo, and defend against some shell metacharacters in $(srcdir). --- doc/autoconf.texi | 351 +++++++++++++++++----------------------------- 1 file changed, 130 insertions(+), 221 deletions(-) diff --git a/doc/autoconf.texi b/doc/autoconf.texi index cc588f499..b8ae02d4f 100644 --- a/doc/autoconf.texi +++ b/doc/autoconf.texi @@ -517,7 +517,6 @@ Portable Shell Programming * Shell Substitutions:: Variable and command expansions * Assignments:: Varying side effects of assignments * Parentheses:: Parentheses in shell scripts -* Slashes:: Slashes in shell scripts * Special Shell Variables:: Variables you should not change * Shell Functions:: What to look out for if you use them * Limitations of Builtins:: Portable use of not so portable /bin/sh @@ -1617,9 +1616,8 @@ are substituted, use: @example @group $ @kbd{autoconf -t AC_SUBST} -configure.ac:2:AC_SUBST:ECHO_C -configure.ac:2:AC_SUBST:ECHO_N -configure.ac:2:AC_SUBST:ECHO_T +configure.ac:28:AC_SUBST:SHELL +configure.ac:28:AC_SUBST:PATH_SEPARATOR @i{More traces deleted} @end group @end example @@ -1650,9 +1648,8 @@ The @var{format} gives you a lot of freedom: @example @group $ @kbd{autoconf -t 'AC_SUBST:$$ac_subst@{"$1"@} = "$f:$l";'} -$ac_subst@{"ECHO_C"@} = "configure.ac:2"; -$ac_subst@{"ECHO_N"@} = "configure.ac:2"; -$ac_subst@{"ECHO_T"@} = "configure.ac:2"; +$ac_subst@{"SHELL"@} = "configure.ac:28"; +$ac_subst@{"PATH_SEPARATOR"@} = "configure.ac:28"; @i{More traces deleted} @end group @end example @@ -2090,15 +2087,15 @@ The @var{copyright-notice} shows up in both the head of Copy revision stamp @var{revision-info} into the @command{configure} script, with any dollar signs or double-quotes removed. This macro lets you put a revision stamp from @file{configure.ac} into @command{configure} -without RCS or CVS changing it when you check in +that the traditional version control systems RCS and CVS can update, +without these systems changing it again when you check in the resulting @command{configure}. That way, you can determine easily which revision of @file{configure.ac} a particular @command{configure} corresponds to. For example, this line in @file{configure.ac}: -@c The @w prevents RCS from changing the example in the manual. @example -AC_REVISION([@w{$}Revision: 1.30 $]) +AC_REVISION([$Revision: 1.30 $]) @end example @noindent @@ -2706,19 +2703,9 @@ how to check the results of previous tests. @ovindex ECHO_C @ovindex ECHO_N @ovindex ECHO_T -How does one suppress the trailing newline from @command{echo} for -question-answer message pairs? These variables provide a way: - -@example -echo $ECHO_N "And the winner is... $ECHO_C" -sleep 100000000000 -echo "$@{ECHO_T@}dead." -@end example - -@noindent -Some old and uncommon @command{echo} implementations offer no means to -achieve this, in which case @code{ECHO_T} is set to tab. You might not -want to use it. +These obsolescent variables let you suppress the trailing newline from +@command{echo} for question-answer message pairs. +Nowadays it is better to use @code{AS_ECHO_N}. @end defvar @defvar ERLCFLAGS @@ -3303,8 +3290,7 @@ package's distribution, so that @command{make} considers @file{config.h.in} up to date. Don't use @command{touch} (@pxref{touch, , Limitations of Usual Tools}); instead, use @command{echo} (using -@command{date} would cause needless differences, hence CVS -conflicts, etc.). +@command{date} would cause needless output differences). @example @group @@ -3731,13 +3717,13 @@ Here is an unrealistic example: @example fubar=42 AC_CONFIG_COMMANDS([fubar], - [echo this is extra $fubar, and so on.], - [fubar=$fubar]) + [AS_ECHO(["this is extra $fubar, and so on."])], + [fubar=$fubar]) @end example Here is a better one: @example -AC_CONFIG_COMMANDS([timestamp], [date >timestamp]) +AC_CONFIG_COMMANDS([timestamp], [echo >timestamp]) @end example @end defmac @@ -4647,8 +4633,7 @@ run. Also, on failure, any action can be performed, whereas @code{AC_CHECK_PROGS} only performs @code{@var{variable}=@var{value-if-not-found}}. -Here is an example, similar to what Autoconf uses in its own configure -script. It will search for an implementation of @command{m4} that +Here is an example that searches for an implementation of @command{m4} that supports the @code{indir} builtin, even if it goes by the name @command{gm4} or is not the first implementation on @env{PATH}. @@ -9093,8 +9078,8 @@ example, to check if library @code{stdlib} is installed: @example AC_ERLANG_CHECK_LIB([stdlib], - [echo "stdlib version \"$ERLANG_LIB_VER_stdlib\"" - echo "is installed in \"$ERLANG_LIB_DIR_stdlib\""], + [AS_ECHO(["stdlib version \"$ERLANG_LIB_VER_stdlib\""]) + AS_ECHO(["is installed in \"$ERLANG_LIB_DIR_stdlib\""])], [AC_MSG_ERROR([stdlib was not found!])]) @end example @@ -9977,7 +9962,7 @@ AC_RUN_IFELSE( [AC_LANG_PROGRAM([], [dnl file:write_file("conftest.out", code:lib_dir()), halt(0)])], - [echo "code:lib_dir() returned: `cat conftest.out`"], + [AS_ECHO(["code:lib_dir() returned: `cat conftest.out`"])], [AC_MSG_FAILURE([test Erlang program execution failed])]) @end example @@ -10604,10 +10589,10 @@ for each kind. The arguments to all of them get enclosed in shell double quotes, so the shell performs variable and back-quote substitution on them. -These macros are all wrappers around the @command{echo} shell command. +These macros are all wrappers around the @command{printf} shell command. They direct output to the appropriate file descriptor (@pxref{File Descriptor Macros}). -@command{configure} scripts should rarely need to run @command{echo} directly +@command{configure} scripts should rarely need to run @command{printf} directly to print messages for the user. Using these macros makes it easy to change how and when each kind of message is printed; such changes need only be made to the macro definitions and all the callers change @@ -11250,7 +11235,7 @@ statement: @example AC_DEFUN([my_case], [case $file_name in - *.c) echo "C source code";; + *.c) file_type='C source code';; esac]) AS_IF(:, my_case) @end example @@ -11266,7 +11251,7 @@ if : then : case $file_name in *.c -fi echo "C source code";; +fi file_type='C source code';; esac) @end example @@ -11280,7 +11265,7 @@ without proper quoting, each with some benefits and some drawbacks. @example AC_DEFUN([my_case], [case $file_name in - (*.c) echo "C source code";; + (*.c) file_type='C source code';; esac]) @end example @noindent @@ -11293,7 +11278,7 @@ available somewhere so this approach typically suffices nowadays. @example AC_DEFUN([my_case], [case $file_name in #( - *.c) echo "C source code";; + *.c) file_type='C source code';; esac]) @end example @noindent @@ -11306,7 +11291,7 @@ that masks the normal properties of @samp{(}. @example AC_DEFUN([my_case], [case $file_name in @@%:@@( - *.c) echo "C source code";; + *.c) file_type='C source code';; esac]) @end example @noindent @@ -11319,7 +11304,7 @@ use of the quadrigraph @samp{@@%:@@} for @samp{#} reduces readability. @example AC_DEFUN([my_case], [case $file_name in - *.c[)] echo "C source code";; + *.c[)] file_type='C source code';; esac]) @end example @noindent @@ -11333,7 +11318,7 @@ terminal. @example AC_DEFUN([my_case], [[case $file_name in #( - *.c) echo "C source code";; + *.c) file_type='C source code';; esac]]) @end example @noindent @@ -11348,7 +11333,7 @@ problems. @example AC_DEFUN([my_case], [AS_CASE([$file_name], - [*.c], [echo "C source code"])]) + [*.c], [file_type='C source code'])]) @end example @noindent This version avoids the balancing issue altogether, by relying on @@ -14018,21 +14003,30 @@ trailing newlines. @defmac AS_ECHO (@var{word}) @asindex{ECHO} -Emits @var{word} to the standard output, followed by a newline. @var{word} -must be a single shell word (typically a quoted string). The bytes of -@var{word} are output as-is, even if it starts with "-" or contains "\". -Redirections can be placed outside the macro invocation. This is much -more portable than using @command{echo} (@pxref{echo, , Limitations of -Shell Builtins}). +Emit @var{word} to the standard output, followed by a newline. +The @var{word} must be a single shell word (typically a quoted string). +Output the shell expansion of @var{word} as-is, +even if it starts with @samp{-} or contains @samp{\}. +Redirections can be placed outside the macro invocation. + +If the shell variable @var{foo} could contain @samp{\} or leading @samp{-}. +@code{AS_ECHO(["$foo"])} is more portable than @command{echo "$foo"}. +@xref{echo, , Limitations of Shell Builtins}. + +Also, @code{AS_ECHO(["$foo"])} is often easier to read than the +@samp{printf '%s\n' "$foo"} that it stands for. +However, because it employs @samp{'} characters, +in contexts where @samp{'} is not allowed +it is better to use @command{printf} directly. +For example, @samp{`eval 'foo=$@{'AS_ESCAPE([[$1]], [`\])'@};printf +"%s\\n" "$foo")'`} would not work if @command{printf} were replaced +with @code{AS_ECHO}. + @end defmac @defmac AS_ECHO_N (@var{word}) @asindex{ECHO_N} -Emits @var{word} to the standard output, without a following newline. -@var{word} must be a single shell word (typically a quoted string) and, -for portability, should not include more than one newline. The bytes of -@var{word} are output as-is, even if it starts with "-" or contains "\". -Redirections can be placed outside the macro invocation. +Act like @code{AS_ECHO(@var{word})}, except do not output a following newline. @end defmac @c We cannot use @dvar because the macro expansion mistreats backslashes. @@ -14253,11 +14247,11 @@ results in a script that will output the line @samp{hello} three times. @example AC_DEFUN([MY_ACTION], [AS_LITERAL_IF([$1], - [echo "$$1"], + [AS_ECHO(["$$1"])], @c $$ [AS_VAR_COPY([var], [$1]) - echo "$var"], - [eval 'echo "$'"$1"\"])]) + AS_ECHO(["$var"])], + [AS_ECHO(["$'"$1"\"])])]) foo=bar bar=hello MY_ACTION([bar]) MY_ACTION([`echo bar`]) @@ -14575,9 +14569,9 @@ The following macros define file descriptors used to output messages For example: @example -echo "$wombats found" >&AS_MESSAGE_LOG_FD -echo 'Enter desired kangaroo count:' >&AS_MESSAGE_FD -read kangaroos <&AS_ORIGINAL_STDIN_FD` +AS_ECHO(["$wombats found"]) >&AS_MESSAGE_LOG_FD +AS_ECHO_N(['Enter desired kangaroo count: ']) >&AS_MESSAGE_FD +read kangaroos <&AS_ORIGINAL_STDIN_FD @end example @noindent @@ -15487,7 +15481,6 @@ subset described above, is fairly portable nowadays. Also please see * Shell Substitutions:: Variable and command expansions * Assignments:: Varying side effects of assignments * Parentheses:: Parentheses in shell scripts -* Slashes:: Slashes in shell scripts * Special Shell Variables:: Variables you should not change * Shell Functions:: What to look out for if you use them * Limitations of Builtins:: Portable use of not so portable /bin/sh @@ -16384,7 +16377,7 @@ For instance, the following code: @example case "$given_srcdir" in -.) top_srcdir="`echo "$dots" | sed 's|/$||'`" ;; +.) top_srcdir="`printf '%s\n' "$dots" | sed 's|/$||'`" ;; *) top_srcdir="$dots$given_srcdir" ;; esac @end example @@ -16394,7 +16387,7 @@ is more readable when written as: @example case $given_srcdir in -.) top_srcdir=`echo "$dots" | sed 's|/$||'` ;; +.) top_srcdir=`printf '%s\n' "$dots" | sed 's|/$||'` ;; *) top_srcdir=$dots$given_srcdir ;; esac @end example @@ -16748,16 +16741,18 @@ a b Finally, Posix states that when mixing @samp{$@{a=b@}} with regular commands, it is unspecified whether the assignments affect the parent shell environment. It is best to perform assignments independently from -commands, to avoid the problems demonstrated in this example: +commands, to avoid the problems demonstrated in this example running on +Solaris 10: @example -$ @kbd{bash -c 'x= y=$@{x:=b@} sh -c "echo +\$x+\$y+";echo -$x-'} +$ @kbd{cmd='x= y=$@{x:=b@} sh -c "echo +\$x+\$y+";printf "%s\\n" -$x-'} +$ @kbd{bash -c "$cmd"} +b+b+ -b- -$ @kbd{/bin/sh -c 'x= y=$@{x:=b@} sh -c "echo +\$x+\$y+";echo -$x-'} +$ @kbd{/bin/sh -c "$cmd"} ++b+ -- -$ @kbd{ksh -c 'x= y=$@{x:=b@} sh -c "echo +\$x+\$y+";echo -$x-'} +$ @kbd{ksh -c "$cmd"} +b+b+ -- @end example @@ -16791,67 +16786,25 @@ problematic string. @item $@{@var{var}=@var{expanded-value}@} @cindex @code{$@{@var{var}=@var{expanded-value}@}} -On Ultrix, -running +On shells so old that they are no longer relevant, the command @example -default="yu,yaa" +# Set the shell variable to a default value +# if it is not already set. : $@{var="$default"@} @end example @noindent -sets @var{var} to @samp{M-yM-uM-,M-yM-aM-a}, i.e., the 8th bit of -each char is set. You don't observe the phenomenon using a simple -@samp{echo $var} since apparently the shell resets the 8th bit when it -expands $var. Here are two means to make this shell confess its sins: - -@example -$ @kbd{cat -v <1 | head -n1} sh: syntax error at line 1: `;' unexpected $ @kbd{make bad list='a b'} @@ -19499,7 +19419,7 @@ Unfortunately this behaves exactly as the original expression; see the Some ancient @command{expr} implementations (e.g., Solaris 10 @command{/usr/ucb/expr}) have a silly length limit that causes @command{expr} to fail if the matched substring is longer than 120 -bytes. In this case, you might want to fall back on @samp{echo|sed} if +bytes. In this case, you might want to fall back on @samp{printf|sed} if @command{expr} fails. Nowadays this is of practical importance only for the rare installer who mistakenly puts @file{/usr/ucb} before @file{/usr/bin} in @env{PATH} on Solaris 10. @@ -20589,10 +20509,10 @@ implementations do not pass the substitution along to submakes. $ @kbd{cat Makefile} foo = foo one: - @@echo $(foo) + @@printf '%s\n' $(foo) $(MAKE) two two: - @@echo $(foo) + @@printf '%s\n' $(foo) $ @kbd{make foo=bar} # GNU make 3.79.1 bar make two @@ -20637,10 +20557,10 @@ you can propagate them to submakes manually, from your makefile: @example foo = foo one: - @@echo $(foo) + @@printf '%s\n' $(foo) $(MAKE) foo=$(foo) two two: - @@echo $(foo) + @@printf '%s\n' $(foo) @end example Another way to propagate a variable to submakes in a portable way is to @@ -20650,10 +20570,10 @@ your makefile: @example foo = foo one: - @@echo $(foo) + @@printf '%s\n' $(foo) $(MAKE) $(SUBMAKEFLAGS) two two: - @@echo $(foo) + @@printf '%s\n' $(foo) @end example Users must be aware that this technique is in use to take advantage of @@ -20681,7 +20601,7 @@ GNU @command{make} it is either @option{--unix} or @example $ @kbd{cat Makefile} all: - @@echo MAKEFLAGS = $(MAKEFLAGS) + @@printf 'MAKEFLAGS = %s\n' '$(MAKEFLAGS)' $ @kbd{make} MAKEFLAGS = --unix $ @kbd{make -k} @@ -20739,8 +20659,8 @@ $ @kbd{cat Makefile} SHELL = /bin/sh FOO = foo all: - @@echo $(SHELL) - @@echo $(FOO) + @@printf '%s\n' '$(SHELL)' + @@printf '%s\n' '$(FOO)' $ @kbd{env SHELL=/bin/tcsh FOO=bar make -e} # Tru64 Make /bin/tcsh bar @@ -20756,7 +20676,7 @@ break this rule: @example $ @kbd{cat Makefile} all: - @@echo $(SHELL) + @@printf '%s\n' '$(SHELL)' @@printenv SHELL $ @kbd{env SHELL=sh make -e SHELL=/bin/ksh} # BSD Make, GNU make 3.80 /bin/ksh @@ -20961,17 +20881,12 @@ together with the backslash that precedes it, by a space in GNU @command{make} 3.80 and older. So, how can a newline be used in a string literal? -The trick is to set up a shell variable that contains a newline: - -@example -nlinit=`echo 'nl="'; echo '"'`; eval "$$nlinit" -@end example - +The trick is to set up a shell variable that contains a newline. For example, in order to create a multi-line @samp{sed} expression that -inserts a blank line after every line of a file, this code can be used: +inserts an empty line after every line of a file, this code can be used: @example -nlinit=`echo 'nl="'; echo '"'`; eval "$$nlinit"; \ +eval $$(printf 'nl="\n"\n'); \ sed -e "s/\$$/\\$$@{nl@}/" < input > output @end example @@ -21688,7 +21603,7 @@ problem, you can use a timestamp file, e.g.: @example dest-stamp: src cp -p src dest - date >dest-stamp + echo >dest-stamp @end example Apart from timestamp resolution, there are also differences in handling @@ -24324,10 +24239,12 @@ Here is an unrealistic example: @example fubar=27 -AC_OUTPUT_COMMANDS([echo this is extra $fubar, and so on.], - [fubar=$fubar]) -AC_OUTPUT_COMMANDS([echo this is another, extra, bit], - [echo init bit]) +AC_OUTPUT_COMMANDS( + [AS_ECHO(["this is extra $fubar, and so on."])], + [fubar=$fubar]) +AC_OUTPUT_COMMANDS( + [AS_ECHO(["this is another, extra, bit"])], + [AS_ECHO(["init bit"])]) @end example Aside from the fact that @code{AC_CONFIG_COMMANDS} requires an @@ -26299,23 +26216,15 @@ Next, add the following lines to your @file{tests/Makefile.am}, in order to link @samp{make check} with a validation suite. @example -# The ':;' works around a Bash 3.2 bug when the output is not writable. $(srcdir)/package.m4: $(top_srcdir)/configure.ac - :;@{ \ - echo '# Signature of the current package.' && \ - echo 'm4_define([AT_PACKAGE_NAME],' && \ - echo ' [$(PACKAGE_NAME)])' && \ - echo 'm4_define([AT_PACKAGE_TARNAME],' && \ - echo ' [$(PACKAGE_TARNAME)])' && \ - echo 'm4_define([AT_PACKAGE_VERSION],' && \ - echo ' [$(PACKAGE_VERSION)])' && \ - echo 'm4_define([AT_PACKAGE_STRING],' && \ - echo ' [$(PACKAGE_STRING)])' && \ - echo 'm4_define([AT_PACKAGE_BUGREPORT],' && \ - echo ' [$(PACKAGE_BUGREPORT)])'; \ - echo 'm4_define([AT_PACKAGE_URL],' && \ - echo ' [$(PACKAGE_URL)])'; \ - @} >'$(srcdir)/package.m4' + printf >'$@@' '%s\n' \ + '# Signature of the current package.' \ + 'm4_define([AT_PACKAGE_NAME], [$(PACKAGE_NAME)])' \ + 'm4_define([AT_PACKAGE_TARNAME], [$(PACKAGE_TARNAME)])' \ + 'm4_define([AT_PACKAGE_VERSION], [$(PACKAGE_VERSION)])' \ + 'm4_define([AT_PACKAGE_STRING], [$(PACKAGE_STRING)])' \ + 'm4_define([AT_PACKAGE_URL], [$(PACKAGE_URL)])' \ + 'm4_define([AT_PACKAGE_BUGREPORT], [$(PACKAGE_BUGREPORT)])' EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) atlocal.in TESTSUITE = $(srcdir)/testsuite @@ -26639,7 +26548,7 @@ Alternatively, create a dedicated header file: @example DISTCLEANFILES = myprog-paths.h myprog-paths.h: Makefile - echo '#define DATADIR "$(datadir)"' >$@@ + printf '%s\n' '#define DATADIR "$(datadir)"' >$@@ @end example @noindent -- 2.47.3