shellescape

package module
v1.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 1, 2026 License: MIT Imports: 4 Imported by: 137

README

shellescape

Build GoDoc sourcegraph codecov

Escape arbitrary strings for safe use as command line arguments.

Contents of the package

This package provides the shellescape.Quote() function that returns a shell-escaped copy of a string. This functionality could be helpful in those cases where it is known that the output of a Go program will be appended to/used in the context of shell programs' command line arguments.

This work was inspired by the Python original package shellescape.

Usage

The following snippet shows a typical unsafe idiom:

package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Printf("ls -l %s\n", os.Args[1])
}

See in Go Playground

Especially when creating pipeline of commands which might end up being executed by a shell interpreter, it is particularly unsafe to not escape arguments.

shellescape.Quote() comes in handy and to safely escape strings:

package main

import (
        "fmt"
        "os"

        "al.essio.dev/pkg/shellescape"
)

func main() {
        fmt.Printf("ls -l %s\n", shellescape.Quote(os.Args[1]))
}

See in Go Playground

The escargs utility

escargs reads lines from the standard input and prints shell-escaped versions. Unlike xargs, blank lines on the standard input are not discarded.

Documentation

Overview

Package shellescape provides the shellescape.Quote to escape arbitrary strings for a safe use as command line arguments in the most common POSIX shells.

The original Python package which this work was inspired by can be found at https://pypi.python.org/pypi/shellescape.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Quote

func Quote(s string) string

Quote returns a shell-escaped version of the string s. The returned value is a string that can safely be used as one token in a shell command line.

Example
package main

import (
	"fmt"
	"strings"

	"al.essio.dev/pkg/shellescape"
)

func main() {
	filename := "myfile; rm -rf /"
	prog := "/bin/ls -lh"
	unsafe := strings.Join([]string{prog, filename}, " ")
	safe := strings.Join([]string{prog, shellescape.Quote(filename)}, " ")

	fmt.Println("unsafe:", unsafe)
	fmt.Println("safe:", safe)

	for i, part := range strings.Split(unsafe, " ") {
		fmt.Printf("unsafe[%d] = %s\n", i, part)
	}

	for i, part := range strings.Split(safe, " ") {
		fmt.Printf("safe[%d] = %s\n", i, part)
	}
}
Output:
unsafe: /bin/ls -lh myfile; rm -rf /
safe: /bin/ls -lh 'myfile; rm -rf /'
unsafe[0] = /bin/ls
unsafe[1] = -lh
unsafe[2] = myfile;
unsafe[3] = rm
unsafe[4] = -rf
unsafe[5] = /
safe[0] = /bin/ls
safe[1] = -lh
safe[2] = 'myfile;
safe[3] = rm
safe[4] = -rf
safe[5] = /'

func QuoteCommand

func QuoteCommand(args []string) string

QuoteCommand returns a shell-escaped version of the slice of strings. The returned value is a string that can safely be used as shell command arguments.

Example
package main

import (
	"fmt"

	"github.com/google/shlex"

	"al.essio.dev/pkg/shellescape"
)

func main() {
	filename := "myfile; rm -rf /"
	unsafe := fmt.Sprintf("ls -l %s", filename)
	command := fmt.Sprintf("ls -l %s", shellescape.Quote(filename))
	splitCommand, _ := shlex.Split(command)

	fmt.Println("unsafe:", unsafe)
	fmt.Println("command:", command)
	fmt.Println("splitCommand:", splitCommand)

	remoteCommandUnsafe := fmt.Sprintf("ssh host.domain %s", command)
	remoteCommand := fmt.Sprintf("ssh host.domain %s", shellescape.Quote(command))
	splitRemoteCommand, _ := shlex.Split(remoteCommand)

	fmt.Println("remoteCommandUnsafe:", remoteCommandUnsafe)
	fmt.Println("remoteCommand:", remoteCommand)
	fmt.Println("splitRemoteCommand:", splitRemoteCommand)

	lastSplit, _ := shlex.Split(splitRemoteCommand[2])
	fmt.Println("lastSplit[0]:", lastSplit[0])
	fmt.Println("lastSplit[1]:", lastSplit[1])
	fmt.Println("lastSplit[2]:", lastSplit[2])

}
Output:
unsafe: ls -l myfile; rm -rf /
command: ls -l 'myfile; rm -rf /'
splitCommand: [ls -l myfile; rm -rf /]
remoteCommandUnsafe: ssh host.domain ls -l 'myfile; rm -rf /'
remoteCommand: ssh host.domain 'ls -l '"'"'myfile; rm -rf /'"'"''
splitRemoteCommand: [ssh host.domain ls -l 'myfile; rm -rf /']
lastSplit[0]: ls
lastSplit[1]: -l
lastSplit[2]: myfile; rm -rf /
Example (Simple)
package main

import (
	"fmt"
	"strings"

	"al.essio.dev/pkg/shellescape"
)

func main() {
	filename := "filename with space"
	prog := "/usr/bin/ls"
	args := "-lh"

	unsafe := strings.Join([]string{prog, args, filename}, " ")
	safe := strings.Join([]string{prog, shellescape.QuoteCommand([]string{args, filename})}, " ")

	fmt.Println("unsafe:", unsafe)
	fmt.Println("safe:", safe)
}
Output:
unsafe: /usr/bin/ls -lh filename with space
safe: /usr/bin/ls -lh 'filename with space'

func ScanTokens added in v1.6.0

func ScanTokens(data []byte, atEOF bool) (advance int, token []byte, err error)

ScanTokens is a split function for a bufio.Scanner that returns each word of text, stripped of amy trailing end-of-text empty byte.

Example
package main

import (
	"bufio"
	"fmt"
	"strings"

	"al.essio.dev/pkg/shellescape"
)

func main() {
	words := "'tis\x00but\x00a\x00scratch!\x00"
	scanner := bufio.NewScanner(strings.NewReader(words))

	scanner.Split(shellescape.ScanTokens)
	for scanner.Scan() {
		fmt.Println(scanner.Text())
	}
}
Output:
'tis
but
a
scratch!

func StripSpaces added in v1.6.1

func StripSpaces(s string) string

StripSpaces removes whitespace characters (e.g., tabs, newlines).

Example
package main

import (
	"fmt"

	"al.essio.dev/pkg/shellescape"
)

func main() {
	s := "   Hello, World    !"
	fmt.Println("Original string:", s)
	fmt.Println("String with spaces stripped:", shellescape.StripSpaces(s))
}
Output:
Original string:    Hello, World    !
String with spaces stripped: Hello,World!
Example (MultipleSpaces)
package main

import (
	"fmt"

	"al.essio.dev/pkg/shellescape"
)

func main() {
	s := "Hello,   World  !"
	fmt.Println("Original string:", s)
	fmt.Println("String with spaces stripped:", shellescape.StripSpaces(s))
}
Output:
Original string: Hello,   World  !
String with spaces stripped: Hello,World!

func StripUnsafe

func StripUnsafe(s string) string

StripUnsafe remove non-printable runes, e.g. control characters in a string that is meant for consumption by terminals that support control characters.

Example
package main

import (
	"fmt"

	"al.essio.dev/pkg/shellescape"
)

func main() {
	safeString := `"printable!" #$%^characters '' 12321312"`
	unsafeString := "these runes shall be removed: \u0000\u0081\u001f"

	fmt.Println("safe:", shellescape.StripUnsafe(safeString))
	fmt.Println("unsafe:", shellescape.StripUnsafe(unsafeString))
}
Output:
safe: "printable!" #$%^characters '' 12321312"
unsafe: these runes shall be removed:

Types

This section is empty.

Directories

Path Synopsis
cmd
escargs command
escargs reads lines from the standard input and prints shell-escaped versions.
escargs reads lines from the standard input and prints shell-escaped versions.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL