3

Say I have the following batch script:

For ... DO (
SET VAL=%%B
IF defined VAL echo %%A=%%B >> %OUTPUT_FILEPATH%
)

How could I get the echo to output using Unix (just line feed) line endings?

Alternatively, could I write the file as-is then convert it from the batch script afterwards? (some kind of find /r/n and replace with /n? If so, how would I do that?)

I'd like a self-contained solution (i.e. one that doesn't involve downloading extra utilities, and can be done from within the batch script itself [Windows 7]).

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
simonalexander2005
  • 3,672
  • 4
  • 39
  • 74
  • I was surprised that I couldn't find this already asked somewhere on SO – simonalexander2005 Nov 25 '16 at 11:26
  • Converting text files to Unix-style line-breaks is actually nothing but outputting each line without trailing line-break, followed by an explicitly output line-feed char.; hence you might find something helpful when searching for something like "echo without new-line" and "new-line character"... – aschipfl Nov 25 '16 at 12:22
  • There is lots on the web about converting Windows text file to unix. If you have my [JREPL.BAT regular expression text processing utility](http://www.dostips.com/forum/viewtopic.php?f=3&t=6044), then you can write the file normally, and then use `call jrepl "^" "" /u /f yourFile.txt /o -`. Or, you can use a pipe to write the file directly in unix format: `yourCommandThatGeneratesFile | jrepl "^" "" /u /o yourFile.txt`. – dbenham Nov 25 '16 at 16:41
  • @dbenham: I don't understand how your `jrepl "^" "" ...` could work. The `"^"` regexp is an [_anchor_](https://msdn.microsoft.com/en-us/library/s48y7b93(v=vs.84).aspx) that match a _position_; it does not match _characters_ (so it can't eliminate they) and, in any case, it match _the beginning_ of lines, not the end as required... – Aacini Nov 26 '16 at 18:24
  • @Aacini - it is somewhat of a hack. The find/replace pair intentionally has no effect. The important bit is the `/U` option that writes all lines with `\n` terminator instead of `\r\n`. I just needed a non-destructive find/replace pair. Downloading JREPL just to convert text to unix form is ludicrous. But it is a useful tool to have for many other situations, and if you happen to have it already, then it can be an efficient and effective tool to do this conversion. I wrote the JREPL solution as a comment instead of an answer precisely because it is a hack. – dbenham Nov 26 '16 at 18:46

3 Answers3

3

The suitable way to perform this conversion is not via a Batch file, but using another programming language, like JScript; this way, the conversion process is fast and reliable. However, you don't need a hundreds lines program in order to achieve a replacement as simple as this one. The two-lines Batch file below do this conversion:

@set @a=0 /* & cscript //nologo //E:JScript "%~F0" < input.txt > output.txt & goto :EOF */

WScript.Stdout.Write(WScript.Stdin.ReadAll().replace(/\r\n/g,"\n"));

EDIT: I added a modification to the original code that allows to include more commands in the Batch part in the standard way.

@set @a=0 /*

@echo off
set "OUTPUT_FILEPATH=C:\Path\Of\The\File.txt"
cscript //nologo //E:JScript "%~F0" < "%OUTPUT_FILEPATH%" > output.txt
move /Y output.txt "%OUTPUT_FILEPATH%"

goto :EOF */

WScript.Stdout.Write(WScript.Stdin.ReadAll().replace(/\r\n/g,"\n"));

The first line is a trick that hide the cscript command from the JScript code, so the compilation of this hybrid .BAT file don't issue errors.

In the JScript code: WScript.Stdin.ReadAll() read the whole redirected input file; this may cause problems if the file is huge. The replace method use a regex to identify the text to replace and put in its place the second string; you may read a further description of this topic at this link. The WScript.Stdout.Write just take the output from replace and send it to the screen. Easy! Isn't it? ;-)

Aacini
  • 59,374
  • 12
  • 63
  • 94
  • +1, but I'm not so sure about the phrase ***"right way"***?! I'd rather see a phrase like "sensible way", It is hard to argue that a batch method that works is "wrong". But I, too, would use JScript, most likely via JREPL, given that it is already in my library of tricks. I prefer to use line processing because JScript is limited to the maximum size it can read into a single string. Reading one line at a time nearly eliminates the size issue. – dbenham Nov 25 '16 at 20:46
  • @dbenham: Well, sometimes I don't choose the best term. I changed it by **_"suitable way"_**... – Aacini Nov 26 '16 at 18:23
  • you say "send it to the screen" - how would I get it into my output file (the same one as it read from?) instead? could you give an example that's specific to my scenario? So I've got a file (stored at %OUTPUT_FILEPATH%) - how would I then replace the endings in that file with your method? – simonalexander2005 Nov 28 '16 at 10:15
  • As you can see in the code, the `> output.txt` part redirects the output "to the screen" from JScript into "output.txt" file, so you just need to add a `move /Y output.txt %OUTPUT_FILEPATH%` command after that... I modified the code accordingly. – Aacini Nov 28 '16 at 19:59
3

If you are OK with using PowerShell, you can produce a Unix newline like this:

PowerShell -Command Write-Host

You can combine this with the SET /P trick to output text without newlines and add newlines manually. For example:

( ECHO | SET /P="Hello World!" & PowerShell -Command Write-Host ) > output.txt

After this, output.txt will contain the text Hello World! with a single 0x0a character appended.

2

Taken from Macros with parameters appended:

Formatting is tricky, but try

set ^"LF=^

^" Don't remove previous line & rem line feed (newline)
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"& rem Define newline with line continuation

For ... DO (
SET VAL=%%B
IF defined VAL <nul set/P^=%%A=%%B%\n%>> %OUTPUT_FILEPATH%
)

Or, to avoid the leading space after first line:

<nul set/P^=%%A=%%B%\n%^>> %OUTPUT_FILEPATH%
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
elzooilogico
  • 1,623
  • 2
  • 13
  • 16
  • tricky might be a good understatement....... any chance you could expand on what that does in your answer? – simonalexander2005 Nov 25 '16 at 11:24
  • @simonalexander2005 sorry, not my native language. depending on what is going to be in `%%A` or `%%B` there may be many characters to escape like the `set/p ^=` – elzooilogico Nov 25 '16 at 11:27
  • There is no need to escape the `=` in `set/P^=`. Change the syntax to `set /P ="%%A=%%B%\n%"`, so (surrounding) quotation marks do no longer get lost. However, leading white-spaces will always get lost. Note that leading `=` signs cause a syntax error. There is actually no secure way using `set /P`, but there are other methods -- see [this answer](http://stackoverflow.com/a/40485255). Or you switch to another language... – aschipfl Nov 25 '16 at 12:16
  • 2
    @simonalexander2005 - A better explanation of `%\n%` can be found at http://stackoverflow.com/a/6379861/1012053 (where jeb calls it `%NL%` instead.). The ` – dbenham Nov 25 '16 at 16:36
  • @dbenham thanks, always something new at your comments! nice post to read! – elzooilogico Nov 25 '16 at 16:55
  • I just realized your `\n` definition is not quite correct for this application - it expands to having a `^` at the end for line continuation, which is not wanted. A better definition is `set ^"\n=^^^%LF%%LF%^%LF%%LF%"` (simply remove the trailing pair of `^^` at the end of the original assignment). – dbenham Nov 25 '16 at 17:15