bash-tpl icon indicating copy to clipboard operation
bash-tpl copied to clipboard

Generated dollar-quote escape sequences are Bash-specific (in practice)

Open 0xEAB opened this issue 1 year ago • 4 comments

For the code

RUN apt-get update && \
	apt-get -y install --no-install-recommends

… Bash-TPL generates:

printf "%s\n" RUN\ apt-get\ update\ \&\&\ \\
printf "%s\n" $'\tapt-get -y install --no-install-recommends'

Which prints

RUN apt-get update && \
$\tapt-get -y install --no-install-recommends

…when run with Dash.

As the readme says, the generated scripts are not supposed to use Bashisms.

The shell scripts that Bash-TPL generates are not intended to be Bash-specific.

The feature in question is, as far as I can tell, part of POSIX 2024, but it’ll be a while until support for it is added to all shells. Dash has committed a patch that adds it just a few hours ago.

I’m not sure whether it’s worth fixing it, but I guess this behavior should be at least documented here on the bug tracker.

0xEAB avatar Jun 23 '24 00:06 0xEAB

Greetings @0xEAB !

Looking into a bit more, i think the issue is that I use %s as the formatter, when I should probably be using %b

Paste this into your DASH shell:

swap %s with %b

printf "%b\n" RUN\ apt-get\ update\ \&\&\ \\
printf "%b\n" $'\tapt-get -y install --no-install-recommends'

%b does appear to be a standard for posix printf:

  • https://www.unix.com/man-page/posix/1posix/printf/

... An additional conversion specifier character, b , shall be supported as follows. The argument shall be taken to be a string that may contain backslash-escape sequences

It appears that many shells treat %s and %b similarly, which is likely why I didn't discover the issue earlier.

This fix is simple, but would technically be a breaking change ...

Just the same I'll put a PR together as it seems like the right thing to do.

If you want to test it out, I believe the change will be: before: line 560

	if [ -n "${args}" ]; then
		printf -v stmt "printf \"%%s\\\\n\" %s" "${args}"
	else
		printf -v stmt "printf \"\\\\n\""
	fi

after

	if [ -n "${args}" ]; then
		printf -v stmt "printf \"%%b\\\\n\" %s" "${args}"
	else
		printf -v stmt "printf \"\\\\n\""
	fi

Feel free to give that a try, and I'll also msg you when the PR is up in case you want to take a test drive before merging.

Thanks for using my project and taking the time to submit an issue!

TekWizely avatar Jun 24 '24 02:06 TekWizely

Running

printf "%b\n" RUN\ apt-get\ update\ \&\&\ \\
printf "%b\n" $'\tapt-get -y install --no-install-recommends'

… with Dash 0.5.12-2 (Debian) prints:

RUN apt-get update && \
$	apt-get -y install --no-install-recommends

0xEAB avatar Jun 25 '24 19:06 0xEAB

This however seems to work:

$ printf "%b\n" '\tapt-get -y install --no-install-recommends'
	apt-get -y install --no-install-recommends

0xEAB avatar Jun 25 '24 19:06 0xEAB

Ugh, you're right - I didn't notice the $ at the start of the line when I tested that :(

OK so I see now that I didn't need %b previously because $'...' is rather equivalent, ie expands escape sequences ...

I think I'll need to find a posix friendly function I can add to the file and call instead of printf %q to escape my strings ...

I'll look into and let you know what I find - Please also share any further research you may do on the matter.

I'm going to leave this issue open but close the MR ...

TekWizely avatar Jun 25 '24 21:06 TekWizely