-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathquote.go
More file actions
66 lines (62 loc) · 1.59 KB
/
quote.go
File metadata and controls
66 lines (62 loc) · 1.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Copyright © 2020 Arista Networks, Inc. All rights reserved.
//
// Use of this source code is governed by the MIT license that can be found
// in the LICENSE file.
package shutil
import (
"strings"
)
// needsQuote returns true if the given character in the given position in a word needs quoting.
func needsQuote(i int, ch rune) bool {
if i == 0 && ch == '~' {
return true
}
return ch == '`' || ch == '$' || ch == '&' || ch == '*' || ch == '(' || ch == ')' ||
ch == '{' || ch == '[' || ch == '\\' || ch == '|' || ch == ' ' ||
ch == ';' || ch == '\'' || ch == '"' || ch == '<' || ch == '>' || ch == '?'
}
// Quote returns a bash command approximating what a human would probably type to invoke the
// given argv array.
// For example, Quote([]string{"rm", "abc def", "hij"}) returns "rm 'abc def' hij".
func Quote(argv []string) string {
var b strings.Builder
first := true
for _, arg := range argv {
if first {
first = false
} else {
b.WriteByte(' ')
}
sawApostrophe := false
needQuoting := false
for i, ch := range arg {
if ch == '\'' {
sawApostrophe = true
break
}
if needsQuote(i, ch) {
needQuoting = true
}
}
if sawApostrophe {
// Word contains an apostrophe. Just backslash-escape everything.
for i, ch := range arg {
if needsQuote(i, ch) {
b.WriteByte('\\')
}
b.WriteRune(ch)
}
} else {
// Word contains no apostrophe. So, use apostrophes to quote, if any
// quoting is needed.
if needQuoting {
b.WriteByte('\'')
}
b.WriteString(arg)
if needQuoting {
b.WriteByte('\'')
}
}
}
return b.String()
}