2

I have to transform the content of a file from \ to \\ on Windows in a script. So I got Coreutils and tried to use tr \ \\ <file_in >file_out on Windows CMD, but \ in file_out remains \ instead of being converted to \\.

The file contains LFs (\n) and CRLFs (\r\n) but they have to remain unchanged. Do a way to use tr to perform the change I tried to do exist?

phuclv
  • 30,396
  • 15
  • 136
  • 260
R. Nec
  • 179

4 Answers4

0

In PowerShell there are lots of ways to do that, GNU tools aren't necessary. For example to do a non-inplace replace like sed "s_\\_\\\\_g" you can loop over each line and replace the strings with String.Replace() or the regex -replace operator like each of the below commands

# Normal literal string replace
PS C:\> (Get-Content -Raw .\file.txt).Replace('\', '\\')
PS C:\> (gc -Ra .\file.txt).Replace('\', '\\') } # Short aliased version of the above

PS C:&gt; Get-Content .\file.txt | ForEach-Object { $.Replace('', '\') } PS C:&gt; gc .\file.txt |% { $.Replace('', '\') }

PS C:&gt; ${c:file.txt}.Replace('', '\') PS C:&gt; [IO.File]::ReadAllText("file.txt").Replace('', '\')

Regex replace, like sed

PS C:&gt; ${c:file.txt} -replace '\','\\' PS C:&gt; cat .\file.txt |% { $_ -replace '\', '\\' } PS C:&gt; [IO.File]::ReadAllText("file.txt") -replace '\','\\'

It's slightly different to do an inplace replace:

PS C:\> (Get-Content -Raw file.txt).Replace("\", "\\") | Set-Content file.txt
PS C:\> (cat -Ra file.txt).Replace("\", "\\") | sc file.txt

PS C:&gt; (Get-Content file.txt) | ForEach-Object { $.Replace("&quot;, "\") } | Set-Content file.txt PS C:&gt; (cat file.txt) |% { $.Replace("&quot;, "\") } | sc file.txt

PS C:&gt; ${c:file.txt} = ${c:file.txt}.Replace('', '\') PS C:&gt; ${c:file.txt} = ${c:file.txt} -replace '\','\\'

Or

PS C:&gt; $content = [IO.File]::ReadAllText("file.txt").Replace("&quot;, "\") PS C:&gt; [IO.File]::WriteAllText("file.txt", $content)

See also

phuclv
  • 30,396
  • 15
  • 136
  • 260
0

tr deals with individual characters, it doesn't really deal with strings, though there is overlap.

you can replace multiple occurrences of a single character, with one occurrence( Replacing \\ with \), an option it calls 'shrink' but you'd want the other way. In theory one could say that involves an individual character just as much, nevertheless, tr cannot do that, it has no option to give it a character and state how many times it should appear. It has that shrink character option but not a repeat character option.

You can use sed, you may find you have to use single quotes rather than double quotes

 $ echo '\' | sed 's_\\_\\\\_g'
\\

or sed 's/a/b/g' filename

syntax with sed with its s command, is sed "s/find/replace/" and putting a g modifier on the end will make sure it doesn't just stop at the first one, it replaces every occurrence. sed 's/find/replace/g' Normally people use / You can use _ i.e. s_a_b_g You don't put a / after the g.

As for \r\n and \n that sed line won't affect it. \r\n is not stored with an actual backslash, it's stored with the binary for the ascii codes it represents. 13 for \r and 10 for \n look at an ascii table and you'd see that.

barlop
  • 25,198
0

Tr translates only single character. To replace it with more than one char it is needed to use sed. It can be found in GnuWin32 - port of linux tools for Windows. To replace \ with \\ you should use f.e.

  cat file | sed "s_\\_\\\\_g" 

The s is for separate mode, g stands for global - in default sed replaces only first occurence in row. \\\\ instead of \\ and \\\\\\\ of \\\\ because backslash has to be escaped using additional backslash.

barlop
  • 25,198
R. Nec
  • 179
0

As others have noted, tr only transforms a single character into another single character.

You can use my JREPL.BAT regular expression text processing utility to easily and efficiently solve your problem. It is pure script (hybrid JScript/batch) that runs natively on any Windows machine from XP onward.

jrepl "\" "\\" /l /f file.txt /o -

The above will write each line with \r\n terminators.

If you must preserve the original line terminators, then you can use the /M multi-line option

jrepl "\" "\\" /l /m /f file.txt /o -

The commands above use the /L literal switch. Without /L, the command interprets the search term as a regular expression, so you would need:

jrepl "\\" "\\" /m /f file.txt /o -

Use call jrepl if you use the command within a batch script.

Interestingly, JREPL has a /T translate option that functions very similarly to the unix tr command. But it is not of any use in your situation.

Use jrepl /? to see the built-in documentation. Pipe the output to more if you want to limit the output to one screen at a time. I don't need more because my console window is configured with a large output buffer so that I can scroll up to see prior output.

dbenham
  • 11,794