user1773603
user1773603

Reputation:

Using "grep -n" and echo : : double backslash interpreted

I want to get the line number of the pattern "\label" with "grep -n" into a file.

The file content is :

\begin{equation}
(\beq{f'_{i}})_{3}-(\beq{e_{i}})_{3}=\text{d}\delta\,\beq{e_{i}}-\delta\,\text{d}\beq{e_{i}}
\label{r58}
\end{equation}

...

\begin{align}
&\beq{mm'_{3}}-\beq{mm_{3}}=\text{d}\delta\,\beq{m}-\delta\,\text{d}\beq{m} 
\label{r59} \\
&(\beq{e'_{i}})_{3}-(\beq{e_{i}})_{3}=\text{d}\delta\,\beq{e_{i}}-\delta\,\text{d}\beq{e_{i}}
\label{r60}
\end{align}

...

\begin{equation}
(\beq{g'_{i}})_{3}-(\beq{e_{i}})_{3}=\text{d}\delta\,\beq{e_{i}}-\delta\,\text{d}\beq{e_{i}}
\label{r61}
\end{equation}

...

The command that I use :

for k in $(grep -n '\\label' test.tex); do echo $k; done

and I get :

...
    1366:\label{r58}
    1376:\label{r59}
    \\
    1378:\label{r60}
    1388:\label{r61}
...

and I want :

...
    1366:\label{r58}
    1376:\label{r59}
    1378:\label{r60}
    1388:\label{r61}
...

Given that I handle after the value of k variable, I would like to skip the line with a double backslash, it seems that "grep -n" interprets the double backslash.

I know that I could do a pipe command on k like "grep -v '\\\\' but can I directly skip this double backslash with grep -n (with an additional flag or with a more explicit pattern) ?

Thanks

Upvotes: 0

Views: 139

Answers (2)

Rany Albeg Wein
Rany Albeg Wein

Reputation: 3474

Since this question is tagged with Bash, I assume you're using the Bash shell.

The following code will take input_file.txt as an input file, and create output_file.txt containing a list of line numbers matching your pattern.

while read -r line;do printf '%s\n' "${line%%:*}";done < <(grep -n --fixed-strings '\label' input_file.txt) > output_file.txt

P.S.

Regarding the code you posted in the question: Never do this: for x in $(command) or command or $var. for-in is used for iterating arguments, not (output) strings. Instead, use a glob (eg. *.txt), arrays (eg. "${names[@]}") or a while-read loop (eg. while read -r line). See http://mywiki.wooledge.org/BashPitfalls#pf1 and http://mywiki.wooledge.org/DontReadLinesWithFor

Upvotes: 0

Benjamin W.
Benjamin W.

Reputation: 52211

You can fix the issue with the newline with

$ for k in "$(grep -n '\\label' text.tex)"; do echo "$k"; done
3:\label{r58}
10:\label{r59} \\
12:\label{r60}
19:\label{r61}

i.e., quoting the command substitution. Which is a very complicated (and not recommended) way of just using

grep -n '\\label' test.tex

as it seems.

If you don't quote the command substitution, its result undergoes word splitting and the \\ is seen as a separate element to loop over, that's why it gets its own line.

To just get the parts you want, you can use

$ grep -on '\\label{[^}]*}' test.tex
3:\label{r58}
10:\label{r59}
12:\label{r60}
19:\label{r61}

-o to just retain the match, and the regex matches the braces after \label as well.

Upvotes: 1

Related Questions