Struct shell_quote::Sh

source ·
pub struct Sh;
Expand description

Quote byte strings for use with /bin/sh.

Notes

The following escapes seem to be “okay”:

\a     alert (bell)
\b     backspace
\f     form feed
\n     new line
\r     carriage return
\t     horizontal tab
\v     vertical tab
\\     backslash
\nnn   the eight-bit character whose value is the octal value nnn

I wasn’t able to find any definitive statement of exactly how Bourne Shell strings should be quoted, mainly because “Bourne Shell” or /bin/sh can refer to many different pieces of software: Bash has a Bourne Shell mode, /bin/sh on Ubuntu is actually Dash, and on macOS 12.3 (and later, and possibly earlier) all bets are off:

sh is a POSIX-compliant command interpreter (shell). It is implemented by re-execing as either bash(1), dash(1), or zsh(1) as determined by the symbolic link located at /private/var/select/sh. If /private/var/select/sh does not exist or does not point to a valid shell, sh will use one of the supported shells.

⚠️ In practice, however, bytes between 0x80 and 0xff inclusive cannot be escaped with \nnn notation. The shell simply ignores these escapes and treats \nnn as a literal string of 4 characters. Hence, in this module, these bytes are reproduced as-is within the quoted string output, with no special escaping.

The code in this module sticks to escape sequences that I consider “standard” by a heuristic known only to me. It operates byte by byte, making no special allowances for multi-byte character sets. In other words, it’s up to the caller to figure out encoding for non-ASCII characters. 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.

If you have some expertise in this area I would love to hear from you.

Implementations§

source§

impl Sh

source

pub fn quote<S: ?Sized + AsRef<[u8]>>(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 quoting is necessary.
  • A quoted string containing ANSI-C-like escapes, like 'foo\nbar'.

See quote_into for a variant that extends an existing Vec instead of allocating a new one.

Examples
assert_eq!(Sh::quote("foobar"), b"foobar");
assert_eq!(Sh::quote("foo bar"), b"'foo bar'");
source

pub fn quote_into<S: ?Sized + AsRef<[u8]>>(s: &S, sout: &mut Vec<u8>)

Quote a string of bytes into an existing Vec<u8>.

See quote for more details.

Examples
let mut buf = Vec::with_capacity(128);
Sh::quote_into("foobar", &mut buf);
buf.push(b' ');  // Add a space.
Sh::quote_into("foo bar", &mut buf);
assert_eq!(buf, b"foobar 'foo bar'");

Trait Implementations§

source§

impl Clone for Sh

source§

fn clone(&self) -> Sh

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Sh

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Copy for Sh

source§

impl Quoter for Sh

Auto Trait Implementations§

§

impl RefUnwindSafe for Sh

§

impl Send for Sh

§

impl Sync for Sh

§

impl Unpin for Sh

§

impl UnwindSafe for Sh

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.