5

One part of /usr/share/X11/xkb/symbols/us starts with xkb_symbols "dvorak" { and ends with the closing curly bracket }; which line-number I want to find.

partial alphanumeric_keys
xkb_symbols "dvorak" {

    name[Group1]= "English (Dvorak)";

    key <TLDE> { [       grave, asciitilde, dead_grave, dead_tilde      ] };

    key <AE01> { [          1,  exclam          ]       };
    key <AE02> { [          2,  at              ]       };
    key <AE03> { [          3,  numbersign      ]       };
    key <AE04> { [          4,  dollar          ]       };
    key <AE05> { [          5,  percent         ]       };
    key <AE06> { [          6,  asciicircum, dead_circumflex, dead_circumflex ] };
    key <AE07> { [          7,  ampersand       ]       };
    key <AE08> { [          8,  asterisk        ]       };
    key <AE09> { [          9,  parenleft,  dead_grave] };
    key <AE10> { [          0,  parenright      ]       };
    key <AE11> { [ bracketleft, braceleft       ]       };
    key <AE12> { [ bracketright, braceright,  dead_tilde] };

    key <AD01> { [  apostrophe, quotedbl, dead_acute, dead_diaeresis    ] };
    key <AD02> { [      comma,  less,   dead_cedilla, dead_caron        ] };
    key <AD03> { [      period, greater, dead_abovedot, periodcentered  ] };
    key <AD04> { [          p,  P               ]       };
    key <AD05> { [          y,  Y               ]       };
    key <AD06> { [          f,  F               ]       };
    key <AD07> { [          g,  G               ]       };
    key <AD08> { [          c,  C               ]       };
    key <AD09> { [          r,  R               ]       };
    key <AD10> { [          l,  L               ]       };
    key <AD11> { [      slash,  question        ]       };
    key <AD12> { [      equal,  plus            ]       };

    key <AC01> { [          a,  A, adiaeresis, Adiaeresis ]     };
    key <AC02> { [          o,  O               ]       };
    key <AC03> { [          e,  E               ]       };
    key <AC04> { [          u,  U               ]       };
    key <AC05> { [          i,  I               ]       };
    key <AC06> { [          d,  D               ]       };
    key <AC07> { [          h,  H               ]       };
    key <AC08> { [          t,  T               ]       };
    key <AC09> { [          n,  N               ]       };
    key <AC10> { [          s,  S               ]       };
    key <AC11> { [      minus,  underscore      ]       };

    key <AB01> { [   semicolon, colon, dead_ogonek, dead_doubleacute ] };
    key <AB02> { [          q,  Q               ]       };
    key <AB03> { [          j,  J               ]       };
    key <AB04> { [          k,  K               ]       };
    key <AB05> { [          x,  X               ]       };
    key <AB06> { [          b,  B               ]       };
    key <AB07> { [          m,  M               ]       };
    key <AB08> { [          w,  W               ]       };
    key <AB09> { [          v,  V               ]       };
    key <AB10> { [          z,  Z               ]       };

    key <BKSL> { [  backslash,  bar             ]       };
};

I can find the start of the environment which returns 192

grep -n 'xkb_symbols "dvorak"' /usr/share/X11/xkb/symbols/us | cut -d ":" -f1 > /tmp/lineNumberStartEnvironment

I do but blank output

# http://unix.stackexchange.com/a/147664/16920
grep -zPo 'pin\(ABC\) (\{([^{}]++|(?1))*\})' /usr/share/X11/xkb/symbols/us

Pseudocode

  1. Go first to the linenumber given by file /tmp/lineNumberStartEnvironment.
  2. Find the closing bracket of the thing located at the line of /tmp/lineNumberStartEnvironment.
    • do this with the data content in the body but also with the complete file /usr/share/X11/xkb/symbols/us

Attempt for heredoc until next line [cas, Kusalananda]

I do where I do not know what I should put to the deliminator; -n returns blank too

sed -n -f - /usr/share/X11/xkb/symbols/us <<END_SED | cut -f1
/xkb_symbols "dvorak" {/,/^};/{
        /xkb_symbols "dvorak" {/=
        /^};/=
}
END_SED

but blank output.

Systems: Ubuntu 16.04
Grep: 2.25

Léo Léopold Hertz 준영
  • 6,788
  • 29
  • 91
  • 193
  • So you're looking for the line number of the line that has just the closing brace for the `xkb_symbols "dvorak"` block, is that right? – Eric Renouf Jun 17 '16 at 13:15
  • Yes. I am looking the line-number of the closing thing as you say. – Léo Léopold Hertz 준영 Jun 17 '16 at 13:22
  • Need details on your question:

    1) Do you need to find the line number of the closing bracket "};" which belongs to the opening bracket for line starting with "xkb_symbols" ?

    2) Will your file be always at the same level of indentation as the one you posted - i.e - will the closing bracket always be at the first column of indentation? What other possible contents of the input file can there be? This will help in providing you a generic bash shell solution to your problem.

    – gawkface Jun 17 '16 at 13:17
  • What do you want to do with the closing bracket? I would use vim . . . `da{` to cut whatever is in the brackets. – Law29 Jun 17 '16 at 20:12
  • @Law29 Vim is not enough here. – Léo Léopold Hertz 준영 Jun 17 '16 at 20:15

2 Answers2

5

This sed script prints the line number of the line matching /^};/ in the range of lines from /xkb_symbols "dvorak" {/ to the next /^};/ (which will be the same }; as the one we get the line number for):

/xkb_symbols "dvorak" {/,/^};/{
        /^};/=
}

If you need both start and end line numbers:

/xkb_symbols "dvorak" {/,/^};/{
        /xkb_symbols "dvorak" {/=
        /^};/=
}

$ sed -n -f tiny_script.sed /usr/share/X11/xkb/symbols/us
192
248

Alternatively:

$ sed -n -f - /usr/share/X11/xkb/symbols/us <<END_SED
/xkb_symbols "dvorak" {/,/^};/{
        /xkb_symbols "dvorak" {/=
        /^};/=
}
END_SED

EDIT: To get these two numbers in a variable, assuming you're using Bash:

pos=( $( sed -n -f - /usr/share/X11/xkb/symbols/us <<END_SED
        /xkb_symbols "dvorak" {/,/^};/{
                /xkb_symbols "dvorak" {/=
                /^};/=
        }
END_SED
) )

echo "start = " ${pos[0]}
echo "end   = " ${pos[1]}

Also, hi! Another Dvorak user!

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
4
#! /usr/bin/awk -f

/"dvorak"/ {dvorak++};

/{/ && dvorak {b++} ;

/}/ && dvorak {b--} ;

dvorak && b == 0 && NR > 1 {
    print NR;
    exit
}

$ ./find-dvorak.awk /usr/share/X11/xkb/symbols/us
248

This uses a counter (b) which gets incremented every time it sees an open-curly-bracket { and decremented whenever it sees a close-curly-bracket }. It also uses a flag variable (dvorak) to know if it is inside the "dvorak" stanza or not.

When b == 0 and the line number is greater than one, print the line number.

BUGS: This does not account for commented-out brackets or those embedded in strings.

If you want the line numbers of the opening AND closing brackets:

#! /usr/bin/awk -f

/"dvorak"/ {dvorak++};

/{/ && dvorak {
    b++;
    if (!first++) {
        print NR
    }
} ;

/}/ && dvorak {b--} ;

dvorak && b == 0 && NR > 1 {
    print NR;
    exit
}

$ ./find-dvorak2.awk /usr/share/X11/xkb/symbols/us
192
248

Here's a version that allows you to search for any xkb_symbols stanza:

#! /usr/bin/awk -f

match($0,"xkb_symbols.*\""search"\"")  {found++};

/{/ && found {
    b++;
    if (!first++) {
        print NR
    }
} ;

/}/ && found {b--} ;

found && b == 0 && NR > 1 {
    print NR;
    exit
}

$ ./find-xkb_symbols.awk -v search=dvorak-intl /usr/share/X11/xkb/symbols/us
255
314
cas
  • 1
  • 7
  • 119
  • 185
  • 1
    There's no reason why you can't do it with `sed`. I think you've misinterpeted @Kusalananda's answer (there is no `>` before the `END_SED`, it's the end of a heredoc, not a redirection). For simple things like this, `awk` vs `sed` is often a matter of personal preference. I like the verbose readability and procedural style of awk. It's easier to read and understand months later. Other times, whether I use `sed` or `awk` (or `perl`) depends on which one i happen to think of first, or which one seems more fitting for the job. – cas Jun 17 '16 at 14:05
  • 1
    also, it would be trivially easy to modify either of the above scripts to search for any stanza, just add `-v search=dvorak-intl` to the command line (before any filenames) when running the script, change the `/"dvorak"/ {dvorak++};` line to `match($0,"\""search"\"") {found++};` and change all other occurences of the `dvorak` variable to `found`. – cas Jun 17 '16 at 14:13
  • 1
    i wouldn't use this script to insert a line. its job is to find a line number. I'd put that line number into a variable (e.g. `$l`), and do something like `printf "%s\n" "${l}i" 'level3(ralt_switch' w | ed filename` – cas Jun 17 '16 at 14:20
  • you want to insert a line before line 69684? use `69684i` in the `printf ... | ed ...` example above. if you're using GNU `ed`, see `info ed` or `pinfo ed` for full docs (the GNU `ed` man page is not much more than a referral to the info docs) – cas Jun 17 '16 at 14:29
  • 1
    One final comment. change both `print NR` lines to `print NR": "$0;` to print the matching lines as well as the line numbers. – cas Jun 17 '16 at 14:33
  • 1
    for info about editing files in-place with `printf` and `ed`: http://unix.stackexchange.com/questions/287593/overwrite-specific-line-in-file-2-with-content-of-file-1/287618#287618 or http://unix.stackexchange.com/questions/281492/how-to-add-a-new-text-line-at-the-first-line-of-a-file/281501#281501 BTW I forgot the `.` before the `w` in my comment above. my mistake, it's required to terminate the insert. – cas Jun 17 '16 at 14:40
  • I did not understand your `printf ... ed` example. I cannot understand your expected outputs there. Etc if you run it on `/usr/share/X11/xkb/symbols/us`. I would like to know what is your expected output. – Léo Léopold Hertz 준영 Jun 17 '16 at 14:54
  • 1
    The `printf | ed` is just a way to make a scripted edit of a file. It's unrelated (in fact, irrelevant) to your actual question. The two links I posted (and many others searchable on this site) explain what the `printf | ed` does and how it works. If you have a specific question about it, then post a new question. It's 1am here, so I'm going to get some sleep...if nobody's answered your new question tomorrow, i'll probably get to it. – cas Jun 17 '16 at 15:03