sh: mvdan.cc/sh/syntax Index | Examples | Files

package syntax

import "mvdan.cc/sh/syntax"

Package syntax implements parsing and formatting of shell programs. It supports both POSIX Shell and Bash.

Code:

r := strings.NewReader("{ foo; bar; }")
f, err := syntax.NewParser().Parse(r, "")
if err != nil {
    return
}
syntax.NewPrinter().Print(os.Stdout, f)

Output:

{
	foo
	bar
}

Index

Examples

Package Files

doc.go expand.go lexer.go nodes.go parser.go pattern.go printer.go quotestate_string.go simplify.go token_string.go tokens.go walk.go

Constants

const (
    RdrOut = RedirOperator(rdrOut) + iota
    AppOut
    RdrIn
    RdrInOut
    DplIn
    DplOut
    ClbOut
    Hdoc
    DashHdoc
    WordHdoc
    RdrAll
    AppAll
)
const (
    CmdIn = ProcOperator(cmdIn) + iota
    CmdOut
)
const (
    GlobQuest = GlobOperator(globQuest) + iota
    GlobStar
    GlobPlus
    GlobAt
    GlobExcl
)
const (
    AndStmt = BinCmdOperator(andAnd) + iota
    OrStmt
    Pipe
    PipeAll
)
const (
    Break = CaseOperator(dblSemicolon) + iota
    Fallthrough
    Resume
    ResumeKorn
)
const (
    NamesPrefix      = ParNamesOperator(star)
    NamesPrefixWords = ParNamesOperator(at)
)
const (
    SubstPlus = ParExpOperator(plus) + iota
    SubstColPlus
    SubstMinus
    SubstColMinus
    SubstQuest
    SubstColQuest
    SubstAssgn
    SubstColAssgn
    RemSmallSuffix
    RemLargeSuffix
    RemSmallPrefix
    RemLargePrefix
    UpperFirst
    UpperAll
    LowerFirst
    LowerAll
    OtherParamOps
)
const (
    Not = UnAritOperator(exclMark) + iota
    Inc
    Dec
    Plus  = UnAritOperator(plus)
    Minus = UnAritOperator(minus)
)
const (
    Add = BinAritOperator(plus)
    Sub = BinAritOperator(minus)
    Mul = BinAritOperator(star)
    Quo = BinAritOperator(slash)
    Rem = BinAritOperator(perc)
    Pow = BinAritOperator(power)
    Eql = BinAritOperator(equal)
    Gtr = BinAritOperator(rdrOut)
    Lss = BinAritOperator(rdrIn)
    Neq = BinAritOperator(nequal)
    Leq = BinAritOperator(lequal)
    Geq = BinAritOperator(gequal)
    And = BinAritOperator(and)
    Or  = BinAritOperator(or)
    Xor = BinAritOperator(caret)
    Shr = BinAritOperator(appOut)
    Shl = BinAritOperator(hdoc)

    AndArit = BinAritOperator(andAnd)
    OrArit  = BinAritOperator(orOr)
    Comma   = BinAritOperator(comma)
    Quest   = BinAritOperator(quest)
    Colon   = BinAritOperator(colon)

    Assgn    = BinAritOperator(assgn)
    AddAssgn = BinAritOperator(addAssgn)
    SubAssgn = BinAritOperator(subAssgn)
    MulAssgn = BinAritOperator(mulAssgn)
    QuoAssgn = BinAritOperator(quoAssgn)
    RemAssgn = BinAritOperator(remAssgn)
    AndAssgn = BinAritOperator(andAssgn)
    OrAssgn  = BinAritOperator(orAssgn)
    XorAssgn = BinAritOperator(xorAssgn)
    ShlAssgn = BinAritOperator(shlAssgn)
    ShrAssgn = BinAritOperator(shrAssgn)
)
const (
    TsExists = UnTestOperator(tsExists) + iota
    TsRegFile
    TsDirect
    TsCharSp
    TsBlckSp
    TsNmPipe
    TsSocket
    TsSmbLink
    TsSticky
    TsGIDSet
    TsUIDSet
    TsGrpOwn
    TsUsrOwn
    TsModif
    TsRead
    TsWrite
    TsExec
    TsNoEmpty
    TsFdTerm
    TsEmpStr
    TsNempStr
    TsOptSet
    TsVarSet
    TsRefVar
    TsNot = UnTestOperator(exclMark)
)
const (
    TsReMatch = BinTestOperator(tsReMatch) + iota
    TsNewer
    TsOlder
    TsDevIno
    TsEql
    TsNeq
    TsLeq
    TsGeq
    TsLss
    TsGtr
    AndTest   = BinTestOperator(andAnd)
    OrTest    = BinTestOperator(orOr)
    TsMatch   = BinTestOperator(equal)
    TsNoMatch = BinTestOperator(nequal)
    TsBefore  = BinTestOperator(rdrIn)
    TsAfter   = BinTestOperator(rdrOut)
)

func BinaryNextLine Uses

func BinaryNextLine(p *Printer)

BinaryNextLine will make binary operators appear on the next line when a binary command, such as a pipe, spans multiple lines. A backslash will be used.

func DebugPrint Uses

func DebugPrint(w io.Writer, node Node) error

DebugPrint prints the provided syntax tree, spanning multiple lines and with indentation. Can be useful to investigate the content of a syntax tree.

Code:

in := strings.NewReader(`echo 'foo'`)
f, err := syntax.NewParser().Parse(in, "")
if err != nil {
    return
}
syntax.DebugPrint(os.Stdout, f)

Output:

*syntax.File {
.  Name: ""
.  StmtList: syntax.StmtList {
.  .  Stmts: []*syntax.Stmt (len = 1) {
.  .  .  0: *syntax.Stmt {
.  .  .  .  Comments: []syntax.Comment (len = 0) {}
.  .  .  .  Cmd: *syntax.CallExpr {
.  .  .  .  .  Assigns: []*syntax.Assign (len = 0) {}
.  .  .  .  .  Args: []*syntax.Word (len = 2) {
.  .  .  .  .  .  0: *syntax.Word {
.  .  .  .  .  .  .  Parts: []syntax.WordPart (len = 1) {
.  .  .  .  .  .  .  .  0: *syntax.Lit {
.  .  .  .  .  .  .  .  .  ValuePos: 1:1
.  .  .  .  .  .  .  .  .  ValueEnd: 1:5
.  .  .  .  .  .  .  .  .  Value: "echo"
.  .  .  .  .  .  .  .  }
.  .  .  .  .  .  .  }
.  .  .  .  .  .  }
.  .  .  .  .  .  1: *syntax.Word {
.  .  .  .  .  .  .  Parts: []syntax.WordPart (len = 1) {
.  .  .  .  .  .  .  .  0: *syntax.SglQuoted {
.  .  .  .  .  .  .  .  .  Left: 1:6
.  .  .  .  .  .  .  .  .  Right: 1:10
.  .  .  .  .  .  .  .  .  Dollar: false
.  .  .  .  .  .  .  .  .  Value: "foo"
.  .  .  .  .  .  .  .  }
.  .  .  .  .  .  .  }
.  .  .  .  .  .  }
.  .  .  .  .  }
.  .  .  .  }
.  .  .  .  Position: 1:1
.  .  .  .  Semicolon: 0:0
.  .  .  .  Negated: false
.  .  .  .  Background: false
.  .  .  .  Coprocess: false
.  .  .  .  Redirs: []*syntax.Redirect (len = 0) {}
.  .  .  }
.  .  }
.  .  Last: []syntax.Comment (len = 0) {}
.  }
}

func HasPattern Uses

func HasPattern(pattern string) bool

HasPattern returns whether a string contains any unescaped wildcard characters: '*', '?', or '['. When the function returns false, the given pattern can only match at most one string.

For example, HasPattern(`foo\*bar`) returns false, but HasPattern(`foo*bar`) returns true.

This can be useful to avoid extra work, like TranslatePattern. Note that this function cannot be used to avoid QuotePattern, as backslashes are quoted by that function but ignored here.

func Indent Uses

func Indent(spaces uint) func(*Printer)

Indent sets the number of spaces used for indentation. If set to 0, tabs will be used instead.

func KeepComments Uses

func KeepComments(p *Parser)

KeepComments makes the parser parse comments and attach them to nodes, as opposed to discarding them.

func KeepPadding Uses

func KeepPadding(p *Printer)

KeepPadding will keep most nodes and tokens in the same column that they were in the original source. This allows the user to decide how to align and pad their code with spaces.

Note that this feature is best-effort and will only keep the alignment stable, so it may need some human help the first time it is run.

func Minify Uses

func Minify(p *Printer)

Minify will print programs in a way to save the most bytes possible. For example, indentation and comments are skipped, and extra whitespace is avoided when possible.

func QuotePattern Uses

func QuotePattern(pattern string) string

QuotePattern returns a string that quotes all special characters in the given wildcard pattern. The returned string is a pattern that matches the literal string.

For example, QuotePattern(`foo*bar?`) returns `foo\*bar\?`.

Code:

wildcard := "foo?bar*"
fmt.Println(wildcard)

quoted := syntax.QuotePattern(wildcard)
fmt.Println(quoted)

expr, err := syntax.TranslatePattern(quoted, true)
if err != nil {
    return
}

rx := regexp.MustCompile(expr)
fmt.Println(rx.MatchString("foo bar baz"))
fmt.Println(rx.MatchString("foo?bar*"))

Output:

foo?bar*
foo\?bar\*
false
true

func Simplify Uses

func Simplify(n Node) bool

Simplify simplifies a given program and returns whether any changes were made.

The changes currently applied are:

Remove clearly useless parentheses       $(( (expr) ))
Remove dollars from vars in exprs        (($var))
Remove duplicate subshells               $( (stmts) )
Remove redundant quotes                  [[ "$var" == str ]]
Merge negations with unary operators     [[ ! -n $var ]]
Use single quotes to shorten literals    "\$foo"

func SpaceRedirects Uses

func SpaceRedirects(p *Printer)

SpaceRedirects will put a space after most redirection operators. The exceptions are '>&', '<&', '>(', and '<('.

func StopAt Uses

func StopAt(word string) func(*Parser)

StopAt configures the lexer to stop at an arbitrary word, treating it as if it were the end of the input. It can contain any characters except whitespace, and cannot be over four bytes in size.

This can be useful to embed shell code within another language, as one can use a special word to mark the delimiters between the two.

As a word, it will only apply when following whitespace or a separating token. For example, StopAt("$$") will act on the inputs "foo $$" and "foo;$$", but not on "foo '$$'".

The match is done by prefix, so the example above will also act on "foo $$bar".

func SwitchCaseIndent Uses

func SwitchCaseIndent(p *Printer)

SwitchCaseIndent will make switch cases be indented. As such, switch case bodies will be two levels deeper than the switch itself.

func TranslatePattern Uses

func TranslatePattern(pattern string, greedy bool) (string, error)

TranslatePattern turns a shell wildcard pattern into a regular expression that can be used with regexp.Compile. It will return an error if the input pattern was incorrect. Otherwise, the returned expression can be passed to regexp.MustCompile.

For example, TranslatePattern(`foo*bar?`, true) returns `foo.*bar.`.

Note that this function (and QuotePattern) should not be directly used with file paths if Windows is supported, as the path separator on that platform is the same character as the escaping character for shell patterns.

Code:

wildcard := "foo?bar*"
fmt.Println(wildcard)

expr, err := syntax.TranslatePattern(wildcard, true)
if err != nil {
    return
}
fmt.Println(expr)

rx := regexp.MustCompile(expr)
fmt.Println(rx.MatchString("foo bar baz"))
fmt.Println(rx.MatchString("foobarbaz"))

Output:

foo?bar*
foo.bar.*
true
false

func ValidName Uses

func ValidName(val string) bool

ValidName returns whether val is a valid name as per the POSIX spec.

func Variant Uses

func Variant(l LangVariant) func(*Parser)

Variant changes the shell language variant that the parser will accept.

func Walk Uses

func Walk(node Node, f func(Node) bool)

Walk traverses a syntax tree in depth-first order: It starts by calling f(node); node must not be nil. If f returns true, Walk invokes f recursively for each of the non-nil children of node, followed by f(nil).

Code:

in := strings.NewReader(`echo $foo "and $bar"`)
f, err := syntax.NewParser().Parse(in, "")
if err != nil {
    return
}
syntax.Walk(f, func(node syntax.Node) bool {
    switch x := node.(type) {
    case *syntax.ParamExp:
        x.Param.Value = strings.ToUpper(x.Param.Value)
    }
    return true
})
syntax.NewPrinter().Print(os.Stdout, f)

Output:

echo $FOO "and $BAR"

type ArithmCmd Uses

type ArithmCmd struct {
    Left, Right Pos
    Unsigned    bool // mksh's ((# expr))
    X           ArithmExpr
}

ArithmCmd represents an arithmetic command.

This node will only appear in LangBash and LangMirBSDKorn.

func (*ArithmCmd) End Uses

func (a *ArithmCmd) End() Pos

func (*ArithmCmd) Pos Uses

func (a *ArithmCmd) Pos() Pos

type ArithmExp Uses

type ArithmExp struct {
    Left, Right Pos
    Bracket     bool // deprecated $[expr] form
    Unsigned    bool // mksh's $((# expr))
    X           ArithmExpr
}

ArithmExp represents an arithmetic expansion.

func (*ArithmExp) End Uses

func (a *ArithmExp) End() Pos

func (*ArithmExp) Pos Uses

func (a *ArithmExp) Pos() Pos

type ArithmExpr Uses

type ArithmExpr interface {
    Node
    // contains filtered or unexported methods
}

ArithmExpr represents all nodes that form arithmetic expressions.

These are *BinaryArithm, *UnaryArithm, *ParenArithm, and *Word.

type ArrayElem Uses

type ArrayElem struct {
    Index    ArithmExpr // [i]=, ["k"]=
    Value    *Word
    Comments []Comment
}

ArrayElem represents a Bash array element.

func (*ArrayElem) End Uses

func (a *ArrayElem) End() Pos

func (*ArrayElem) Pos Uses

func (a *ArrayElem) Pos() Pos

type ArrayExpr Uses

type ArrayExpr struct {
    Lparen, Rparen Pos
    Elems          []*ArrayElem
    Last           []Comment
}

ArrayExpr represents a Bash array expression.

This node will only appear with LangBash.

func (*ArrayExpr) End Uses

func (a *ArrayExpr) End() Pos

func (*ArrayExpr) Pos Uses

func (a *ArrayExpr) Pos() Pos

type Assign Uses

type Assign struct {
    Append bool // +=
    Naked  bool // without '='
    Name   *Lit
    Index  ArithmExpr // [i], ["k"]
    Value  *Word      // =val
    Array  *ArrayExpr // =(arr)
}

Assign represents an assignment to a variable.

Here and elsewhere, Index can mean either an index expression into an indexed array, or a string key into an associative array.

If Index is non-nil, the value will be a word and not an array as nested arrays are not allowed.

If Naked is true and Name is nil, the assignment is part of a DeclClause and the assignment expression (in the Value field) will be evaluated at run-time.

func (*Assign) End Uses

func (a *Assign) End() Pos

func (*Assign) Pos Uses

func (a *Assign) Pos() Pos

type BinAritOperator Uses

type BinAritOperator token

func (BinAritOperator) String Uses

func (o BinAritOperator) String() string

type BinCmdOperator Uses

type BinCmdOperator token

func (BinCmdOperator) String Uses

func (o BinCmdOperator) String() string

type BinTestOperator Uses

type BinTestOperator token

func (BinTestOperator) String Uses

func (o BinTestOperator) String() string

type BinaryArithm Uses

type BinaryArithm struct {
    OpPos Pos
    Op    BinAritOperator
    X, Y  ArithmExpr
}

BinaryArithm represents a binary arithmetic expression.

If Op is any assign operator, X will be a word with a single *Lit whose value is a valid name.

Ternary operators like "a ? b : c" are fit into this structure. Thus, if Op==Quest, Y will be a *BinaryArithm with Op==Colon. Op can only be Colon in that scenario.

func (*BinaryArithm) End Uses

func (b *BinaryArithm) End() Pos

func (*BinaryArithm) Pos Uses

func (b *BinaryArithm) Pos() Pos

type BinaryCmd Uses

type BinaryCmd struct {
    OpPos Pos
    Op    BinCmdOperator
    X, Y  *Stmt
}

BinaryCmd represents a binary expression between two statements.

func (*BinaryCmd) End Uses

func (b *BinaryCmd) End() Pos

func (*BinaryCmd) Pos Uses

func (b *BinaryCmd) Pos() Pos

type BinaryTest Uses

type BinaryTest struct {
    OpPos Pos
    Op    BinTestOperator
    X, Y  TestExpr
}

BinaryTest represents a binary test expression.

func (*BinaryTest) End Uses

func (b *BinaryTest) End() Pos

func (*BinaryTest) Pos Uses

func (b *BinaryTest) Pos() Pos

type Block Uses

type Block struct {
    Lbrace, Rbrace Pos
    StmtList
}

Block represents a series of commands that should be executed in a nested scope.

func (*Block) End Uses

func (b *Block) End() Pos

func (*Block) Pos Uses

func (b *Block) Pos() Pos

type CStyleLoop Uses

type CStyleLoop struct {
    Lparen, Rparen   Pos
    Init, Cond, Post ArithmExpr
}

CStyleLoop represents the behaviour of a for clause similar to the C language.

This node will only appear with LangBash.

func (*CStyleLoop) End Uses

func (c *CStyleLoop) End() Pos

func (*CStyleLoop) Pos Uses

func (c *CStyleLoop) Pos() Pos

type CallExpr Uses

type CallExpr struct {
    Assigns []*Assign // a=x b=y args
    Args    []*Word
}

CallExpr represents a command execution or function call, otherwise known as a "simple command".

If Args is empty, Assigns apply to the shell environment. Otherwise, they are variables that cannot be arrays and which only apply to the call.

func (*CallExpr) End Uses

func (c *CallExpr) End() Pos

func (*CallExpr) Pos Uses

func (c *CallExpr) Pos() Pos

type CaseClause Uses

type CaseClause struct {
    Case, Esac Pos
    Word       *Word
    Items      []*CaseItem
    Last       []Comment
}

CaseClause represents a case (switch) clause.

func (*CaseClause) End Uses

func (c *CaseClause) End() Pos

func (*CaseClause) Pos Uses

func (c *CaseClause) Pos() Pos

type CaseItem Uses

type CaseItem struct {
    Op       CaseOperator
    OpPos    Pos // unset if it was finished by "esac"
    Comments []Comment
    Patterns []*Word
    StmtList
}

CaseItem represents a pattern list (case) within a CaseClause.

func (*CaseItem) End Uses

func (c *CaseItem) End() Pos

func (*CaseItem) Pos Uses

func (c *CaseItem) Pos() Pos

type CaseOperator Uses

type CaseOperator token

func (CaseOperator) String Uses

func (o CaseOperator) String() string

type CmdSubst Uses

type CmdSubst struct {
    Left, Right Pos
    StmtList

    TempFile bool // mksh's ${ foo;}
    ReplyVar bool // mksh's ${|foo;}
}

CmdSubst represents a command substitution.

func (*CmdSubst) End Uses

func (c *CmdSubst) End() Pos

func (*CmdSubst) Pos Uses

func (c *CmdSubst) Pos() Pos

type Command Uses

type Command interface {
    Node
    // contains filtered or unexported methods
}

Command represents all nodes that are simple or compound commands, including function declarations.

These are *CallExpr, *IfClause, *WhileClause, *ForClause, *CaseClause, *Block, *Subshell, *BinaryCmd, *FuncDecl, *ArithmCmd, *TestClause, *DeclClause, *LetClause, *TimeClause, and *CoprocClause.

Code:

r := strings.NewReader("echo foo; if x; then y; fi; foo | bar")
f, err := syntax.NewParser().Parse(r, "")
if err != nil {
    return
}

printer := syntax.NewPrinter()
for i, stmt := range f.Stmts {
    fmt.Printf("Cmd %d: %-20T - ", i, stmt.Cmd)
    printer.Print(os.Stdout, stmt.Cmd)
    fmt.Println()
}

Output:

Cmd 0: *syntax.CallExpr     - echo foo
Cmd 1: *syntax.IfClause     - if x; then y; fi
Cmd 2: *syntax.BinaryCmd    - foo | bar

type Comment Uses

type Comment struct {
    Hash Pos
    Text string
}

Comment represents a single comment on a single line.

func (*Comment) End Uses

func (c *Comment) End() Pos

func (*Comment) Pos Uses

func (c *Comment) Pos() Pos

type CoprocClause Uses

type CoprocClause struct {
    Coproc Pos
    Name   *Lit
    Stmt   *Stmt
}

CoprocClause represents a Bash coproc clause.

This node will only appear with LangBash.

func (*CoprocClause) End Uses

func (c *CoprocClause) End() Pos

func (*CoprocClause) Pos Uses

func (c *CoprocClause) Pos() Pos

type DblQuoted Uses

type DblQuoted struct {
    Position Pos
    Dollar   bool // $""
    Parts    []WordPart
}

DblQuoted represents a list of nodes within double quotes.

func (*DblQuoted) End Uses

func (q *DblQuoted) End() Pos

func (*DblQuoted) Pos Uses

func (q *DblQuoted) Pos() Pos

type DeclClause Uses

type DeclClause struct {
    // Variant is one of "declare", "local", "export", "readonly",
    // "typeset", or "nameref".
    Variant *Lit
    Opts    []*Word
    Assigns []*Assign
}

DeclClause represents a Bash declare clause.

This node will only appear with LangBash.

func (*DeclClause) End Uses

func (d *DeclClause) End() Pos

func (*DeclClause) Pos Uses

func (d *DeclClause) Pos() Pos

type Expansion Uses

type Expansion struct {
    Op   ParExpOperator
    Word *Word
}

Expansion represents string manipulation in a ParamExp other than those covered by Replace.

type ExtGlob Uses

type ExtGlob struct {
    OpPos   Pos
    Op      GlobOperator
    Pattern *Lit
}

ExtGlob represents a Bash extended globbing expression. Note that these are parsed independently of whether shopt has been called or not.

This node will only appear in LangBash and LangMirBSDKorn.

func (*ExtGlob) End Uses

func (e *ExtGlob) End() Pos

func (*ExtGlob) Pos Uses

func (e *ExtGlob) Pos() Pos

type File Uses

type File struct {
    Name string

    StmtList
}

File represents a shell source file.

func (*File) End Uses

func (f *File) End() Pos

func (*File) Pos Uses

func (f *File) Pos() Pos

type ForClause Uses

type ForClause struct {
    ForPos, DoPos, DonePos Pos
    Select                 bool
    Loop                   Loop
    Do                     StmtList
}

ForClause represents a for or a select clause. The latter is only present in Bash.

func (*ForClause) End Uses

func (f *ForClause) End() Pos

func (*ForClause) Pos Uses

func (f *ForClause) Pos() Pos

type FuncDecl Uses

type FuncDecl struct {
    Position Pos
    RsrvWord bool // non-posix "function f()" style
    Name     *Lit
    Body     *Stmt
}

FuncDecl represents the declaration of a function.

func (*FuncDecl) End Uses

func (f *FuncDecl) End() Pos

func (*FuncDecl) Pos Uses

func (f *FuncDecl) Pos() Pos

type GlobOperator Uses

type GlobOperator token

func (GlobOperator) String Uses

func (o GlobOperator) String() string

type IfClause Uses

type IfClause struct {
    Elif    bool // whether this IfClause begins with "elif"
    IfPos   Pos  // position of the starting "if" or "elif" token
    ThenPos Pos
    ElsePos Pos // position of a following "else" or "elif", if any
    FiPos   Pos // position of "fi", empty if Elif == true

    Cond StmtList
    Then StmtList
    Else StmtList

    ElseComments []Comment // comments on the "else"
    FiComments   []Comment // comments on the "fi"
}

IfClause represents an if statement.

func (*IfClause) End Uses

func (c *IfClause) End() Pos

func (*IfClause) FollowedByElif Uses

func (c *IfClause) FollowedByElif() bool

FollowedByElif reports whether this IfClause is followed by an "elif" IfClause in its Else branch. This is true if Else.Stmts has exactly one statement with an IfClause whose Elif field is true.

func (*IfClause) Pos Uses

func (c *IfClause) Pos() Pos

type LangError Uses

type LangError struct {
    Filename string
    Pos
    Feature string
    Langs   []LangVariant
}

LangError is returned when the parser encounters code that is only valid in other shell language variants. The error includes what feature is not present in the current language variant, and what languages support it.

func (LangError) Error Uses

func (e LangError) Error() string

type LangVariant Uses

type LangVariant int
const (
    LangBash LangVariant = iota
    LangPOSIX
    LangMirBSDKorn
)

func (LangVariant) String Uses

func (l LangVariant) String() string

type LetClause Uses

type LetClause struct {
    Let   Pos
    Exprs []ArithmExpr
}

LetClause represents a Bash let clause.

This node will only appear in LangBash and LangMirBSDKorn.

func (*LetClause) End Uses

func (l *LetClause) End() Pos

func (*LetClause) Pos Uses

func (l *LetClause) Pos() Pos

type Lit Uses

type Lit struct {
    ValuePos, ValueEnd Pos
    Value              string
}

Lit represents a string literal.

Note that a parsed string literal may not appear as-is in the original source code, as it is possible to split literals by escaping newlines. The splitting is lost, but the end position is not.

func (*Lit) End Uses

func (l *Lit) End() Pos

func (*Lit) Pos Uses

func (l *Lit) Pos() Pos

type Loop Uses

type Loop interface {
    Node
    // contains filtered or unexported methods
}

Loop holds either *WordIter or *CStyleLoop.

type Node Uses

type Node interface {
    // Pos returns the position of the first character of the node. Comments
    // are ignored, except if the node is a *File.
    Pos() Pos
    // End returns the position of the character immediately after the node.
    // If the character is a newline, the line number won't cross into the
    // next line. Comments are ignored, except if the node is a *File.
    End() Pos
}

Node represents a syntax tree node.

type ParExpOperator Uses

type ParExpOperator token

func (ParExpOperator) String Uses

func (o ParExpOperator) String() string

type ParNamesOperator Uses

type ParNamesOperator token

func (ParNamesOperator) String Uses

func (o ParNamesOperator) String() string

type ParamExp Uses

type ParamExp struct {
    Dollar, Rbrace Pos
    Short          bool // $a instead of ${a}
    Excl           bool // ${!a}
    Length         bool // ${#a}
    Width          bool // ${%a}
    Param          *Lit
    Index          ArithmExpr       // ${a[i]}, ${a["k"]}
    Slice          *Slice           // ${a:x:y}
    Repl           *Replace         // ${a/x/y}
    Names          ParNamesOperator // ${!prefix*} or ${!prefix@}
    Exp            *Expansion       // ${a:-b}, ${a#b}, etc
}

ParamExp represents a parameter expansion.

func (*ParamExp) End Uses

func (p *ParamExp) End() Pos

func (*ParamExp) Pos Uses

func (p *ParamExp) Pos() Pos

type ParenArithm Uses

type ParenArithm struct {
    Lparen, Rparen Pos
    X              ArithmExpr
}

ParenArithm represents an arithmetic expression within parentheses.

func (*ParenArithm) End Uses

func (p *ParenArithm) End() Pos

func (*ParenArithm) Pos Uses

func (p *ParenArithm) Pos() Pos

type ParenTest Uses

type ParenTest struct {
    Lparen, Rparen Pos
    X              TestExpr
}

ParenTest represents a test expression within parentheses.

func (*ParenTest) End Uses

func (p *ParenTest) End() Pos

func (*ParenTest) Pos Uses

func (p *ParenTest) Pos() Pos

type ParseError Uses

type ParseError struct {
    Filename string
    Pos
    Text string
}

ParseError represents an error found when parsing a source file, from which the parser cannot recover.

func (ParseError) Error Uses

func (e ParseError) Error() string

type Parser Uses

type Parser struct {
    // contains filtered or unexported fields
}

Parser holds the internal state of the parsing mechanism of a program.

func NewParser Uses

func NewParser(options ...func(*Parser)) *Parser

NewParser allocates a new Parser and applies any number of options.

Code:

src := "for ((i = 0; i < 5; i++)); do echo $i >f; done"

// LangBash is the default
r := strings.NewReader(src)
f, err := syntax.NewParser().Parse(r, "")
fmt.Println(err)

// Parser errors with LangPOSIX
r = strings.NewReader(src)
_, err = syntax.NewParser(syntax.Variant(syntax.LangPOSIX)).Parse(r, "")
fmt.Println(err)

syntax.NewPrinter().Print(os.Stdout, f)
syntax.NewPrinter(syntax.SpaceRedirects).Print(os.Stdout, f)

Output:

<nil>
1:5: c-style fors are a bash feature
for ((i = 0; i < 5; i++)); do echo $i >f; done
for ((i = 0; i < 5; i++)); do echo $i > f; done

func (*Parser) Document Uses

func (p *Parser) Document(r io.Reader) (*Word, error)

Document parses a single here-document word. That is, it parses the input as if they were lines following a <<EOF redirection.

In practice, this is the same as parsing the input as if it were within double quotes, but without having to escape all double quote characters. Similarly, the here-document word parsed here cannot be ended by any delimiter other than reaching the end of the input.

func (*Parser) Incomplete Uses

func (p *Parser) Incomplete() bool

func (*Parser) Interactive Uses

func (p *Parser) Interactive(r io.Reader, fn func([]*Stmt) bool) error

Interactive implements what is necessary to parse statements in an interactive shell. The parser will call the given function under two circumstances outlined below.

If a line containing any number of statements is parsed, the function will be called with said statements.

If a line ending in an incomplete statement is parsed, the function will be called with any fully parsed statents, and Parser.Incomplete will return true.

One can imagine a simple interactive shell implementation as follows:

fmt.Fprintf(os.Stdout, "$ ")
parser.Interactive(os.Stdin, func(stmts []*syntax.Stmt) bool {
        if parser.Incomplete() {
                fmt.Fprintf(os.Stdout, "> ")
                return true
        }
        run(stmts)
        fmt.Fprintf(os.Stdout, "$ ")
        return true
}

If the callback function returns false, parsing is stopped and the function is not called again.

func (*Parser) Parse Uses

func (p *Parser) Parse(r io.Reader, name string) (*File, error)

Parse reads and parses a shell program with an optional name. It returns the parsed program if no issues were encountered. Otherwise, an error is returned. Reads from r are buffered.

Parse can be called more than once, but not concurrently. That is, a Parser can be reused once it is done working.

func (*Parser) Stmts Uses

func (p *Parser) Stmts(r io.Reader, fn func(*Stmt) bool) error

Stmts reads and parses statements one at a time, calling a function each time one is parsed. If the function returns false, parsing is stopped and the function is not called again.

func (*Parser) Words Uses

func (p *Parser) Words(r io.Reader, fn func(*Word) bool) error

Words reads and parses words one at a time, calling a function each time one is parsed. If the function returns false, parsing is stopped and the function is not called again.

Newlines are skipped, meaning that multi-line input will work fine. If the parser encounters a token that isn't a word, such as a semicolon, an error will be returned.

Note that the lexer doesn't currently tokenize spaces, so it may need to read a non-space byte such as a newline or a letter before finishing the parsing of a word. This will be fixed in the future.

type Pos Uses

type Pos struct {
    // contains filtered or unexported fields
}

Pos is a position within a shell source file.

func (Pos) After Uses

func (p Pos) After(p2 Pos) bool

After reports whether the position p is after p2. It is a more expressive version of p.Offset() > p2.Offset().

func (Pos) Col Uses

func (p Pos) Col() uint

Col returns the column number of the position, starting at 1. It counts in bytes.

func (Pos) IsValid Uses

func (p Pos) IsValid() bool

IsValid reports whether the position is valid. All positions in nodes returned by Parse are valid.

func (Pos) Line Uses

func (p Pos) Line() uint

Line returns the line number of the position, starting at 1.

func (Pos) Offset Uses

func (p Pos) Offset() uint

Offset returns the byte offset of the position in the original source file. Byte offsets start at 0.

func (Pos) String Uses

func (p Pos) String() string

type Printer Uses

type Printer struct {
    // contains filtered or unexported fields
}

Printer holds the internal state of the printing mechanism of a program.

func NewPrinter Uses

func NewPrinter(options ...func(*Printer)) *Printer

NewPrinter allocates a new Printer and applies any number of options.

func (*Printer) Print Uses

func (p *Printer) Print(w io.Writer, node Node) error

Print "pretty-prints" the given syntax tree node to the given writer. Writes to w are buffered.

The node types supported at the moment are *File, *Stmt, *Word, any Command node, and any WordPart node. A trailing newline will only be printed when a *File is used.

type ProcOperator Uses

type ProcOperator token

func (ProcOperator) String Uses

func (o ProcOperator) String() string

type ProcSubst Uses

type ProcSubst struct {
    OpPos, Rparen Pos
    Op            ProcOperator
    StmtList
}

ProcSubst represents a Bash process substitution.

This node will only appear with LangBash.

func (*ProcSubst) End Uses

func (s *ProcSubst) End() Pos

func (*ProcSubst) Pos Uses

func (s *ProcSubst) Pos() Pos

type RedirOperator Uses

type RedirOperator token

func (RedirOperator) String Uses

func (o RedirOperator) String() string

type Redirect Uses

type Redirect struct {
    OpPos Pos
    Op    RedirOperator
    N     *Lit  // fd>, or {varname}> in Bash
    Word  *Word // >word
    Hdoc  *Word // here-document body
}

Redirect represents an input/output redirection.

func (*Redirect) End Uses

func (r *Redirect) End() Pos

func (*Redirect) Pos Uses

func (r *Redirect) Pos() Pos

type Replace Uses

type Replace struct {
    All        bool
    Orig, With *Word
}

Replace represents a search and replace expression inside a ParamExp.

type SglQuoted Uses

type SglQuoted struct {
    Left, Right Pos
    Dollar      bool // $''
    Value       string
}

SglQuoted represents a string within single quotes.

func (*SglQuoted) End Uses

func (q *SglQuoted) End() Pos

func (*SglQuoted) Pos Uses

func (q *SglQuoted) Pos() Pos

type Slice Uses

type Slice struct {
    Offset, Length ArithmExpr
}

Slice represents a character slicing expression inside a ParamExp.

This node will only appear in LangBash and LangMirBSDKorn.

type Stmt Uses

type Stmt struct {
    Comments   []Comment
    Cmd        Command
    Position   Pos
    Semicolon  Pos  // position of ';', '&', or '|&', if any
    Negated    bool // ! stmt
    Background bool // stmt &
    Coprocess  bool // mksh's |&

    Redirs []*Redirect // stmt >a <b
}

Stmt represents a statement, also known as a "complete command". It is compromised of a command and other components that may come before or after it.

func (*Stmt) End Uses

func (s *Stmt) End() Pos

func (*Stmt) Pos Uses

func (s *Stmt) Pos() Pos

type StmtList Uses

type StmtList struct {
    Stmts []*Stmt
    Last  []Comment
}

StmtList is a list of statements with any number of trailing comments. Both lists can be empty.

type Subshell Uses

type Subshell struct {
    Lparen, Rparen Pos
    StmtList
}

Subshell represents a series of commands that should be executed in a nested shell environment.

func (*Subshell) End Uses

func (s *Subshell) End() Pos

func (*Subshell) Pos Uses

func (s *Subshell) Pos() Pos

type TestClause Uses

type TestClause struct {
    Left, Right Pos
    X           TestExpr
}

TestClause represents a Bash extended test clause.

This node will only appear in LangBash and LangMirBSDKorn.

func (*TestClause) End Uses

func (t *TestClause) End() Pos

func (*TestClause) Pos Uses

func (t *TestClause) Pos() Pos

type TestExpr Uses

type TestExpr interface {
    Node
    // contains filtered or unexported methods
}

TestExpr represents all nodes that form test expressions.

These are *BinaryTest, *UnaryTest, *ParenTest, and *Word.

type TimeClause Uses

type TimeClause struct {
    Time        Pos
    PosixFormat bool
    Stmt        *Stmt
}

TimeClause represents a Bash time clause. PosixFormat corresponds to the -p flag.

This node will only appear in LangBash and LangMirBSDKorn.

func (*TimeClause) End Uses

func (c *TimeClause) End() Pos

func (*TimeClause) Pos Uses

func (c *TimeClause) Pos() Pos

type UnAritOperator Uses

type UnAritOperator token

func (UnAritOperator) String Uses

func (o UnAritOperator) String() string

type UnTestOperator Uses

type UnTestOperator token

func (UnTestOperator) String Uses

func (o UnTestOperator) String() string

type UnaryArithm Uses

type UnaryArithm struct {
    OpPos Pos
    Op    UnAritOperator
    Post  bool
    X     ArithmExpr
}

UnaryArithm represents an unary arithmetic expression. The unary opearator may come before or after the sub-expression.

If Op is Inc or Dec, X will be a word with a single *Lit whose value is a valid name.

func (*UnaryArithm) End Uses

func (u *UnaryArithm) End() Pos

func (*UnaryArithm) Pos Uses

func (u *UnaryArithm) Pos() Pos

type UnaryTest Uses

type UnaryTest struct {
    OpPos Pos
    Op    UnTestOperator
    X     TestExpr
}

UnaryTest represents a unary test expression. The unary opearator may come before or after the sub-expression.

func (*UnaryTest) End Uses

func (u *UnaryTest) End() Pos

func (*UnaryTest) Pos Uses

func (u *UnaryTest) Pos() Pos

type WhileClause Uses

type WhileClause struct {
    WhilePos, DoPos, DonePos Pos
    Until                    bool
    Cond                     StmtList
    Do                       StmtList
}

WhileClause represents a while or an until clause.

func (*WhileClause) End Uses

func (w *WhileClause) End() Pos

func (*WhileClause) Pos Uses

func (w *WhileClause) Pos() Pos

type Word Uses

type Word struct {
    Parts []WordPart
}

Word represents a shell word, containing one or more word parts contiguous to each other. The word is delimeted by word boundaries, such as spaces, newlines, semicolons, or parentheses.

Code:

r := strings.NewReader("echo foo${bar}'baz'")
f, err := syntax.NewParser().Parse(r, "")
if err != nil {
    return
}

printer := syntax.NewPrinter()
args := f.Stmts[0].Cmd.(*syntax.CallExpr).Args
for i, word := range args {
    fmt.Printf("Word number %d:\n", i)
    for _, part := range word.Parts {
        fmt.Printf("%-20T - ", part)
        printer.Print(os.Stdout, part)
        fmt.Println()
    }
    fmt.Println()
}

Output:

Word number 0:
*syntax.Lit          - echo

Word number 1:
*syntax.Lit          - foo
*syntax.ParamExp     - ${bar}
*syntax.SglQuoted    - 'baz'

func ExpandBraces Uses

func ExpandBraces(word *Word) []*Word

ExpandBraces performs Bash brace expansion on a word. For example, passing it a single-literal word "foo{bar,baz}" will return two single-literal words, "foobar" and "foobaz".

Deprecated: use mvdan.cc/sh/expand.Braces instead.

func (*Word) End Uses

func (w *Word) End() Pos

func (*Word) Lit Uses

func (w *Word) Lit() string

Lit returns the word as a literal value, if the word consists of *syntax.Lit nodes only. An empty string is returned otherwise. Words with multiple literals, which can appear in some edge cases, are handled properly.

For example, the word "foo" will return "foo", but the word "foo${bar}" will return "".

func (*Word) Pos Uses

func (w *Word) Pos() Pos

type WordIter Uses

type WordIter struct {
    Name  *Lit
    Items []*Word
}

WordIter represents the iteration of a variable over a series of words in a for clause.

func (*WordIter) End Uses

func (w *WordIter) End() Pos

func (*WordIter) Pos Uses

func (w *WordIter) Pos() Pos

type WordPart Uses

type WordPart interface {
    Node
    // contains filtered or unexported methods
}

WordPart represents all nodes that can form part of a word.

These are *Lit, *SglQuoted, *DblQuoted, *ParamExp, *CmdSubst, *ArithmExp, *ProcSubst, and *ExtGlob.

Package syntax imports 10 packages (graph) and is imported by 16 packages. Updated 2018-12-07. Refresh now. Tools for package owners.