pub struct Bash;Expand description
Quote byte strings for use with Bash, the GNU Bourne-Again Shell.
§Compatibility
Quoted/escaped strings produced by Bash work in both Bash and Z Shell.
§⚠️ Warning regarding NUL
It is possible to encode NUL in a Bash string, but Bash appears to then truncate the rest of the string after that point or sometimes it filters the NUL out. It’s not yet clear to me when/why each behaviour is chosen.
If you’re quoting UTF-8 content this may not be a problem since there is only one code point – the null character itself – that will ever produce a NUL byte. To avoid this problem entirely, consider using Modified UTF-8 so that the NUL byte can never appear in a valid byte stream.
§⚠️ Warning regarding % and job control in Bash
A word beginning with % cannot be made safe to use as a command
name in Bash, by this crate or by any other means. In command position
Bash reads such a word as a job specification: %1 on its
own is shorthand for fg %1.
Quoting does not prevent it, because Bash tests the word’s value, after
expansion and quote removal. Every one of these runs fg:
%1 '%1' "%1" $'%1' \%1 ""%1Nor is it conditional on job control being enabled. Bash rewrites the word
either way; all that changes is which complaint you get, fg: no job control or fg: %1: no such job. It behaves this same way with job control
off, with set -m, with set +m, under --posix, and in Bash 3.2 as
shipped by Apple. Put an executable named %1 on PATH and Bash will not
run it, though it will run it happily by an explicit path.
It is the first character that matters, and only the first: %1, %foo,
%, %%, %+, %-, and %?x are all intercepted, while a%1 is an
ordinary command name.
Z Shell differs: it tests the literal token, so there quoting does prevent
it, and all of the above but the first are ordinary command names. This
crate quotes % unconditionally, which is what Z Shell needs, and is at
worst harmless in Bash.
Keep it in proportion, though: this bites only in command position. As an
argument – which is what this crate is mostly used for – % is an
ordinary character in both shells, and printf %s $'%1' prints %1 as you
would expect.
If you are interpolating an untrusted string into command position, quoting is not sufficient protection in any case; prefer to invoke a known command and pass the string as an argument.
§Notes
From bash(1):
Words of the form $‘string’ are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard. Backslash escape sequences, if present, are decoded as follows:
\a alert (bell)
\b backspace
\e an escape character
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\' single quote
\nnn the eight-bit character whose value is the
octal value nnn (one to three digits)
\xHH the eight-bit character whose value is the
hexadecimal value HH (one or two hex digits)
\cx a control-x characterBash allows, in newer versions, for non-ASCII Unicode characters with
\uHHHH and \UXXXXXXXX syntax inside these ANSI C quoted
strings, but we avoid this and work only with bytes. Part
of the problem is that it’s not clear how Bash then works with these
strings. Does it encode these characters into bytes according to the user’s
current locale? Are strings in Bash now natively Unicode?
For now it’s up to the caller to figure out encoding. A significant use case for this code is to quote filenames into scripts, and on *nix variants I understand that filenames are essentially arrays of bytes, even if the OS adds some normalisation and case-insensitivity on top.
Implementations§
Source§impl Bash
impl Bash
Sourcepub fn quote_vec<'a, S: Into<Quotable<'a>>>(s: S) -> Vec<u8> ⓘ
pub fn quote_vec<'a, S: Into<Quotable<'a>>>(s: S) -> Vec<u8> ⓘ
Quote a string of bytes into a new Vec<u8>.
This will return one of the following:
- The string as-is, if no escaping is necessary.
- An ANSI-C escaped string, like
$'foo\nbar'.
See quote_into_vec for a variant that
extends an existing Vec instead of allocating a new one.
§Examples
assert_eq!(Bash::quote_vec("foobar"), b"foobar");
assert_eq!(Bash::quote_vec("foo bar"), b"$'foo bar'");