Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am using perl to parse many multilingual text files. I need to change the text between two patterns:

Desired Changes

For example, the English original version looks like this:

\label{whatever}
\ref{whatever}
\autoref{whatever}

but the stuff between {and } should be suffixed with the appropriate ISO 639 language code e.g.

\label{whatever_de}
\ref{whatever_de}
\autoref{whatever_de}

Assumptions for Testing

Given the following files:

da/myfile_da.tex
de/myfile_de.tex
el/myfile_el.tex
en/myfile_en.tex

and each file contains:

\label{some_nice_thing}
\ref{some_nice_thing}
\autoref{some_nice_thing}

My Approach

I can use folder names as my ISO 639 codes and create a simple loop through the files. The following should simply print the changed lines to the terminal console. I will try to explain the peculiar results I am getting by example:

Working: \\label\{.*?\}

for f in *; do  if [[ -d $f ]]; then perl -ne "print if s/(\\label\{.*?)\}/\1_$f\}/g"  $f/myfile_$f.tex; fi; done

Not Working: \\ref\{.*?\}

for f in *; do  if [[ -d $f ]]; then perl -ne "print if s/(\\ref\{.*?)\}/\1_$f\}/g"  $f/myfile_$f.tex; fi; done

Not Working: \\autoref\{.*?\}

for f in *; do  if [[ -d $f ]]; then perl -ne "print if s/(\\autoref\{.*?)\}/\1_$f\}/g"  $f/myfile_$f.tex; fi; done

Note that grep -Pr works with each case (removing groups, of course)

share|improve this question
up vote 2 down vote accepted

It's a quoting problem. You're using double quotes for the $f variable, but double quotes also have other implications. In particular, they allow backslash-escaping of characters, so \\ becomes \ when it reaches Perl:

$ printf "%s\n" "print if s/(\\label\{.*?)\}/\1_$f\}/g"
print if s/(\label\{.*?)\}/\1_\}/g

This creates a problem with r, because \r will be seen as the return character (see perlrebackslash) - it won't match r. Use single quotes instead, only opening for the variable:

$ printf "%s\n" 'print if s/(\\label\{.*?)\}/\1_'"$f"'\}/g'
print if s/(\\label\{.*?)\}/\1_\}/g
share|improve this answer

\\ becomes \ in double quotes. \\ref becomes \ref which is in fact \r followed by ef. Use four backslashes:

for f in *; do
    if [[ -d $f ]]; then
        perl -ne "print if s/(\\\\ref\{.*?)\}/\1_$f\}/g" $f/SystemRequirements_$f.tex
    fi
done

Similarly, \a is the BELL character (\x07).

share|improve this answer
    
Thanks! Your answer is great for the extra info. I accepted muru's answer because it also answers correctly and accurately and was first. But I am sure the alternative \\\\ and \x07 will come in handy for some future readers. – macmadness86 Feb 17 at 21:28
    
Do you know why in-place editing does not work here e.g. perl -ei? Obviously, this is above and beyond the original question. – macmadness86 Feb 17 at 21:38
2  
@macmadness86: -ei is wrong, code must follow e. – choroba Feb 17 at 21:40

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.