我有下面这个批处理文件,它是 Unix 命令的简单模拟head
——它将读取第一个数数来自输入 .csv 文件的行(以命令行参数命名)。但是,与 Unix 命令不同,它会写入硬编码的输出文件。现在唯一的问题是,这个批处理文件将被多次调用来创建这个输出文件,并将继续将结果附加到输出文件中。我无法更改 to,>>
因为>
这是一个for
循环,只会继续将一行覆盖到我的输出文件中,这是不正确的。有人知道如何在每次运行批处理文件时覆盖输出 .csv 文件吗?
@echo off
if [%1] == [] goto usage
if [%2] == [] goto usage
call :print_head %1 %2
goto :eof
REM
REM print_head
REM Prints the first non-blank %1 lines in the file %2.
REM
:print_head
setlocal EnableDelayedExpansion
set /a counter=0
for /f ^"usebackq^ eol^=^
^ delims^=^" %%a in (%2) do (
if "!counter!"=="%1" goto :eof
@echo>>trimmed.csv %%a
set /a counter+=1
)
goto :eof
:usage
echo Usage: head.bat COUNT FILENAME
答案1
我个人更愿意用“无内容”覆盖该文件,而不是删除该文件:
type NUL>trimmed.csv
将其放置在环上方的某个位置。
这将创建一个空白文件,或用名为 的空文件覆盖现有文件trimmed.csv
。由于这是覆盖,而不是删除并重新创建,因此它应该保留原始文件的创建日期。
答案2
也许只是在批次开始时(或在:print_head 部分的顶部)将其删除?
就像是del trimmed.csv /Q
。
这样,它会在下次运行时被删除,但在循环运行时仍会被创建并附加。
答案3
我知道这是一个老问题;然而,因为我没有看到这个潜在的答案,所以我还是添加它了,因为它可能是某些人的首选答案......
而不仅仅是:
@echo>>trimmed.csv %%a
如上所述,它只会附加现有的输出文件,请尝试使用:
if [[ "$counter" -eq 0 ]]; then
@echo > trimmed.csv %%a
else
@echo >> trimmed.csv %%a
fi
这样,您就不必担心检查文件是否存在,如果存在则删除它。此外,在输出的第一行,它会自动将现有文件覆盖为新的空文件,如果不存在则启动一个新文件,然后它会附加其余行。
但是,就我个人而言,我可能会使用一些格式化的日期附加或添加到文件基名(即 2018-11-17_trimmed.csv 或 trimmed_2018-11-17.csv)并使用“date”命令的输出填充到变量中(这样“date”就不会在每次循环迭代中运行),甚至两者兼而有之。
答案4
这是一个(在我看来)更简单、更直接的方法:将整个for
循环放在括号中,并将 I/O 重定向移到括号外 — 而 >
不是 >>
:
(
for /f ^"usebackq^ eol^=^
^ delims^=^" %%a in (%2) do (
if "!counter!"=="%1" goto :eof
@echo %%a
set /a counter+=1
)
) > trimmed.csv
因此,当循环开始时,文件将打开进行写入(如果文件已经存在/仍然存在,则破坏先前的内容)。然后,批处理文件将在整个循环期间将 CSV 文件保持打开作为标准输出,因此从循环内部写入标准输出的任何内容都将进入 CSV 文件。
这甚至可能比批处理文件的原始版本效率更高,因为那个(可能)必须打开和关闭输出文件数数次,而我的版本只需要执行一次。