Skip to content

Instantly share code, notes, and snippets.

@x-yuri
Last active December 28, 2024 12:08
Show Gist options
  • Save x-yuri/751d58683b683a23986b43e97765ebc1 to your computer and use it in GitHub Desktop.
Save x-yuri/751d58683b683a23986b43e97765ebc1 to your computer and use it in GitHub Desktop.
bash: backticks and a backslash

bash: backticks and a backslash

Before executing a command in backticks certain preprocessing takes place:

  • \\ becomes \ (`echo \\\\` -> echo \\ -> \)
  • but if there's a \ not followed by \, then \ remains \ (`echo \\\ ` -> echo \\ -> \)
  • unquoted \ at the end of the resulting command remains \ (`echo \\` -> echo \ -> \), but this is not exactly about backticks (bash -c 'echo \' -> \)
  • \" remains \" (`echo \"` -> echo \" -> ")
  • but in double quotes \" becomes " ("`echo \\\"`" -> echo \" -> ")
  • \$ becomes $ (`a=1; echo \$a` -> a=1; echo $a -> 1)
  • \` becomes ` (`echo \`echo \\\\\\\\\`` -> echo `echo \\\\` -> \)
  • for a nested command substitution of level n the rules above apply n times (take echo \\\\\\\\ from the previous rule, apply the first rule twice and you get echo \\, which produces \)

a.bats:

strict() { set -euo pipefail; shopt -s inherit_errexit; "$@"; }

setup() {
    [ "$BATS_LIB_PATH" = /usr/lib/bats ] && BATS_LIB_PATH=$HOME/.bats/lib:$BATS_LIB_PATH
    bats_load_library bats-support
    bats_load_library bats-assert
    strict
}

# unquoted \\ becomes \
@test "unquoted \\\\ becomes \\" {
    a=`echo \\\\`  # |echo \\|
    assert_equal "$a" '\'
}

# unquoted \ remains \
@test "unquoted \\ remains \\" {
    a=`echo \\\ `  # |echo \\ |
    assert_equal "$a" '\'
}

# unquoted \ at the end of the resulting command remains \
@test "unquoted \\ at the end of the resulting command remains \\" {
    a=`echo \\`  # |echo \|
    assert_equal "$a" '\'
}

# single-quoted \ remains \
@test "single-quoted \\ remains \\" {
    a=`echo '\'`  # |echo '\'|
    assert_equal "$a" '\'
}

# single-quoted \\ becomes \
@test "single-quoted \\\\ becomes \\" {
    a=`echo '\\'`  # |echo '\'|
    assert_equal "$a" '\'
}

# double-quoted \\ becomes \
@test "double-quoted \\\\ becomes \\" {
    a=`echo "\\\\"`  # |echo "\\"|
    assert_equal "$a" '\'
}

# unquoted \" remains \"
@test "unquoted \\\" remains \\\"" {
    a=`echo \"`  # |echo \"|
    assert_equal "$a" '"'
}

# unquoted \" inside double quotes becomes "
@test "unquoted \\\" inside double quotes becomes \"" {
    a="`echo \\\"`"  # |echo \"|
    assert_equal "$a" '"'
}

# single-quoted \" remains \"
@test "single-quoted \\\" remains \\\"" {
    a=`echo '\"'`  # |echo '\"'|
    assert_equal "$a" '\"'
}

# single-quoted \" inside double quotes becomes "
@test "single-quoted \\\" inside double quotes becomes \"" {
    a="`echo '\"'`"  # |echo '"'|
    assert_equal "$a" '"'
}

# double-quoted \" remains \"
@test "double-quoted \\\" remains \\\"" {
    a=`echo "\""`  # |echo "\""|
    assert_equal "$a" '"'
}

# double-quoted \" inside double quotes becomes "
@test "double-quoted \\\" inside double quotes becomes \"" {
    a="`echo "\\\""`"  # |echo "\""|
    assert_equal "$a" '"'
}

# unquoted \$ becomes $
@test "unquoted \\\$ becomes \$" {
    a=`a=1; echo \$a`  # |echo $a|
    assert_equal "$a" '1'
}

# single-quoted \$ becomes $
@test "single-quoted \\\$ becomes \$" {
    a=`a=1; echo '\$a'`  # |echo '$a'|
    assert_equal "$a" '$a'
}

# double-quoted \$ becomes $
@test "double-quoted \\\$ becomes \$" {
    a=`a=1; echo "\$a"`  # |echo "$a"|
    assert_equal "$a" '1'
}

# nested: unquoted \\ becomes \
@test "nested: unquoted \\\\ becomes \\" {
    a=`echo \`echo \\\\\\\\\``  # |echo `echo \\\\`| -> |echo \\|
    assert_equal "$a" '\'
}

# nested: unquoted \ remains \
@test "nested: unquoted \\ remains \\" {
    a=`echo \`echo \\\\\\ \``  # |echo `echo \\\ `| -> |echo \\ |
    assert_equal "$a" '\'
}

# nested: unquoted \ at the end of the resulting command remains \
@test "nested: unquoted \\ at the end of the resulting command remains \\" {
    a=`echo \`echo \\\\\``  # |echo `echo \\`| -> |echo \|
    assert_equal "$a" '\'
}

# nested: single-quoted \ remains \
@test "nested: single-quoted \\ remains \\" {
    a=`echo \`echo '\'\``  # |echo `echo '\'`| -> |echo '\'|
    assert_equal "$a" '\'
}

# nested: single-quoted \\ becomes \
@test "nested: single-quoted \\\\ becomes \\" {
    a=`echo \`echo '\\\\'\``  # |echo `echo '\\'`| -> |echo '\'|
    assert_equal "$a" '\'
}

# nested: double-quoted \\ becomes \
@test "nested: double-quoted \\\\ becomes \\" {
    a=`echo \`echo "\\\\\\\\"\``  # |echo `echo "\\\\"`| -> |echo "\\"|
    assert_equal "$a" '\'
}

# nested: unquoted \" remains \"
@test "nested: unquoted \\\" remains \\\"" {
    a=`echo \`echo \"\``  # |echo `echo \"`| -> |echo \"|
    assert_equal "$a" '"'
}

# nested: unquoted \" inside double quotes becomes "
@test "nested: unquoted \\\" inside double quotes becomes \"" {
    a=`echo "\`echo \\\\\"\`"`  # |echo "`echo \\\"`"| -> |echo \"|
    assert_equal "$a" '"'
}

# nested: single-quoted \" remains \"
@test "nested: single-quoted \\\" remains \\\"" {
    a=`echo \`echo '\"'\``  # |echo `echo '\"'`| -> |echo '\"'|
    assert_equal "$a" '\"'
}

# nested: single-quoted \" inside double quotes becomes "
@test "nested: single-quoted \\\" inside double quotes becomes \"" {
    a=`echo "\`echo '\"'\`"`  # |echo "`echo '\"'`"| -> |echo '"'|
    assert_equal "$a" '"'
}

# nested: double-quoted \" remains \"
@test "nested: double-quoted \\\" remains \\\"" {
    a=`echo \`echo "\""\``  # |echo `echo "\""`| -> |echo "\""|
    assert_equal "$a" '"'
}

# nested: double-quoted \" inside double quotes becomes "
@test "nested: double-quoted \\\" inside double quotes becomes \"" {
    a=`echo "\`echo "\\\\\""\`"`  # |echo "`echo "\\\""`"| -> |echo "\""|
    assert_equal "$a" '"'
}

# nested: unquoted \$ becomes $
@test "nested: unquoted \\\$ becomes \$" {
    a=`a=1; echo \`echo \\\$a\``  # |echo `echo \$a`| -> |echo $a|
    assert_equal "$a" '1'
}

# nested: single-quoted \$ becomes $
@test "nested: single-quoted \\\$ becomes \$" {
    a=`a=1; echo \`echo '\\\$a'\``  # |echo `echo '\$a'`| -> |echo '$a'|
    assert_equal "$a" '$a'
}

# nested: double-quoted \$ becomes $
@test "nested: double-quoted \\\$ becomes \$" {
    a=`a=1; echo \`echo "\\\$a"\``  # |echo `echo "\$a"`| -> |echo "$a"|
    assert_equal "$a" '1'
}
$ docker run --rm -itv "$PWD":/app -w /app alpine:3.21
/ # apk add git bash ncurses
/ # git clone https://github.com/bats-core/bats-core ~/.bats
/ # git clone https://github.com/bats-core/bats-support ~/.bats/lib/bats-support
/ # git clone https://github.com/bats-core/bats-assert ~/.bats/lib/bats-assert
/ # ~/.bats/bin/bats a.bats
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment