When bash is called with the name sh, it does this:
if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0')
act_like_sh++;
and then later sets the POSIXLY_CORRECT shell variable to y:
if (act_like_sh)
{
bind_variable ("POSIXLY_CORRECT", "y", 0);
sv_strict_posix ("POSIXLY_CORRECT");
}
bind_variable calls bind_variable_internal, which, if the shell attribute a is on at the time (which it would be if you invoked the shell with -a), marks the shell variable as exported.
So in your first script:
#!/bin/sh -a
echo "a" | sed -e 's/[\d001-\d008]//g'
sed is invoked with POSIXLY_CORRECT=y in its environment, which will make it complain about [\d001-\d008]. (Same thing happens if sed is given the --posix option.)
In GNU sed, \dNNN is an escape code for the character whose numerical value in base-10 is NNN, but in POSIX mode, this is disabled inside a bracket expression, so [\d001-\d008], means literally the characters \, d, etc., with the range being from 1 to \. In order of character codes, 1 comes before \ (and the range includes all digits except zero, plus all uppercase letters, plus some special characters). In the en_US.UTF-8 locale which you were using, \ sorts before 1, however, so the range is invalid.
In your second script:
#!/bin/sh
set -a
echo "a" | sed -e 's/[\d001-\d008]//g'
even though POSIXLY_CORRECT is set in the shell, it isn't exported, so sed is invoked without POSIXLY_CORRECT in the environment, and sed runs with GNU extensions.
If you add export POSIXLY_CORRECT near the top of your second script, you'll also see sed complain.
share the same. Nor all sed are equivalent. Whichshare you using? In which OS? and Which sed (maybe?sed --versionif it doesn't fail)?LC_COLLATE=C(orPOSIX) for the call tosedworks around the issuePOSIXLY_CORRECT=yin the environment, the second does not havePOSIXLY_CORRECTin the environment. The shell I invoke both scripts from does not havePOSIXLY_CORRECTin its environment.echo "a" | POSIXLY_CORRECT=y sed -e 's/[\d001-\d008]//g'reproduce your problem