1

I am trying to extract bin names from from Cargo.toml using Bash, I enabled perl regular expression like this

First attempt

grep -Pzo '(?<=(^\[\[bin\]\]))\s*name\s*=\s*"(.*)"' ./Cargo.toml

The regular expression is tested at regex101 enter image description here But got nothing

the Pzo options usage can be found here

Second attempt

grep -P (?<=(^[[bin]]))\n*\sname\s=\s*"(.*)" ./Cargo.toml

Still nothing

grep -Pzo '(?<=(^\[\[bin\]\]))\s*name\s*=\s*"(.*)"' ./Cargo.toml

Cargo.toml

[[bin]]
name = "acme1"
path = "bin/acme1.rs"

[[bin]]
name = "acme2"
path = "src/acme1.rs"
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
Vidy Videni
  • 1,897
  • 3
  • 15
  • 23
  • Since this is tagged rust, why not write a small binary that just parses the file (using https://crates.io/crates/toml) and outputs the names? ;-) – mhutter Nov 12 '21 at 15:26

2 Answers2

0

With your shown samples and attempts, please try following code with tac + awk combination, which will be easier to maintain and does the job with easiness, which will be difficult in grep.

tac Input_file | 
awk '
  /^name =/{
    gsub(/"/,"",$NF)
    value=$NF
    next
  }
  /^path[[:space:]]+=[[:space:]]+"bin\//{
    print value
    value=""
  }
' | 
tac

Explanation: Adding detailed explanation for above code.

tac Input_file |                             ##Using tac command on Input_file to print it in bottom to top order.
awk '                                        ##passing tac output to awk as standard input.
  /^name =/{                                 ##Checking if line starts from name = then do following.
    gsub(/"/,"",$NF)                         ##Globally substituting " with NULL in last field.
    value=$NF                                ##Setting value to last field value here.
    next                                     ##next will skip all further statements from here.
  }
  /^path[[:space:]]+=[[:space:]]+"bin\//{    ##Checking if line starts from path followed by space = followed by spaces followed by "bin/ here.
    print value                              ##printing value here.
    value=""                                 ##Nullifying value here.
  }
' |                                          ##Passing awk program output as input to tac here. 
tac                                          ##Printing values in their actual order.
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
0

grep:

grep -A1 '^\[\[bin\]\]$' |
grep -Po '(?<=^name = ")[^"]*(?=".*)'

or if you can use awk, this is more robust

awk '
$1 ~ /^\[\[?[[:alnum:]]*\]\]?$/{
    if ($1=="[[bin]]" || $1=="[bin]") {bin=1}
    else {bin=0}
}
bin==1 &&
sub(/^[[:space:]]*name[[:space:]]*=[[:space:]]*/, "") {
    sub(/^"/, ""); sub(/".*$/, "")
    print
}' cargo.toml

Example:

$ cat cargo.toml
[[bin]]
name = "acme1"
path = "bin/acme1.rs"

[bin]
name="acme2"

[[foo]]
name = "nobin"

    [bin]
not_name = "hello"
name="acme3"
path = "src/acme3.rs"

[[bin]]
path = "bin/acme4.rs"
name = "acme4" # a comment

$ sh solution
acme1
acme2
acme3
acme4

Obviously, these are no substitute for a real toml parser.

dan
  • 4,846
  • 6
  • 15