2

I have set of 5000 CSV files in tree directory structure. Every file was first row denoting its enconding, then typical CSV content follows.

UTF-8
Key1,"Value 1",
Key2,"Value 2"
etc, etc...

How can I quickly collect first row from each file in order to oversee set of their encodings?

I'm trying this with help of this answer but I don't clearly understand all syntax nuances of batch file variables so I am getting stuff like Echo is on.

for /R D:\resources\ %%f in (*.csv) do (
    set /p line1=<%%f
    echo %line1% >> out.txt
)

If parts are executed individually (for single file), they work.

I was also trying single-liner

for /R D:\resources\ %f in (*.csv) do set /p line1=<%f & echo %line1% >> out.txt

but this one put value collected from first file into output from each file.

miroxlav
  • 11,796
  • 5
  • 58
  • 99
  • 1
    You are getting `Echo is on.` because `%line1%` appears empty. Enable [delayed expansion](http://ss64.com/nt/delayedexpansion.html) as you write *and* read the variable in the same block of code. Finally, change your `echo` command line to `>> out.txt echo(!line1!`. – aschipfl Jun 04 '17 at 12:52
  • 1
    @aschipfl - that helped. Would you like to add it as answer? I'll accept it. – miroxlav Jun 04 '17 at 13:05

2 Answers2

2

The main problem here is the lack of delayed expansion, which is needed when you write and read a variable within the same block of code; without it, you are reading the variable value present when parsing the block, so before it is executed. Here is the fixed code:

@echo off
copy NUL out.txt
setlocal EnableDelayedExpansion
for /R "D:\resources" %%g in ("*.csv") do (
    set "line1="
    < "%%~g" set /P line1=""
    >> "out.txt" echo(!line1!
)
endlocal

In addition, I quoted all file/directory paths in order to avoid trouble with white-spaces or special characters in them. I also reversed the redirection syntax, because echo(!line1! >> "out.txt" also outputs the SPACE in front of >>. The ( instead of a SPACE behind echo looks odd but prevents ECHO is {on|off}. being returned when the read line in !line1! is empty.

By the way, you do not need to prepare an empty output file out.txt initially, you can simply redirect the whole for loop into the output files once using >, given that you put a surrounding pair of parentheses:

@echo off
setlocal EnableDelayedExpansion
> "out.txt" (
    for /R "D:\resources" %%g in (*.csv) do (
        set "line1="
        < "%%~g" set /P line1=""
        echo(!line1!
    )
)
endlocal

To do the same directly in command prompt as a single-liner, try this:

cmd /V /C (for /R "D:\resources" %g in ("*.csv") do @(set "line1=" ^& ^< "%~g" set /P line1="" ^& echo(!line1!)) ^> "out.txt"
aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • Man... this is greatly qualified answer. This is also how script files packed by tricks of the pro's become difficult to read for recreational scripters. :) I bookmarked this Q/A to return to these techniques next time. Thank you for optimization and its explanation. – miroxlav Jun 04 '17 at 15:54
0

aschipfl's comment helped. Adding corrected and completed script for benefit of others:

@echo off
copy NUL out.txt
SETLOCAL EnableDelayedExpansion
for /R D:\resources\ %%g in (*.csv) do (
  set /p line1=<%%g
  echo !line1! >> out.txt
)
miroxlav
  • 11,796
  • 5
  • 58
  • 99