Windows批处理文件-删除前导字符

时间:2018-12-04 19:05:03

标签: windows loops batch-file substring

我有一个批处理文件,可以使用gsutil工具将一些本地文件复制到google存储区。 gsutil工具会生成一个漂亮的日志文件,其中显示了上载的文件的详细信息以及是否正常。

Source,Destination,Start,End,Md5,UploadId,Source Size,Bytes Transferred,Result,Description
file://C:\TEMP\file_1.xlsx,gs://app1/backups/file_1.xlsx,2018-12-04T15:25:48.428000Z,2018-12-04T15:25:48.804000Z,CPHHZfdlt6AePAPz6JO2KQ==,,18753,18753,OK,
file://C:\TEMP\file_2.xlsx,gs://app1/backups/file_2.xlsx,2018-12-04T15:25:48.428000Z,2018-12-04T15:25:48.813000Z,aTKCOQSPVwDycM9+NGO28Q==,,18753,18753,OK,

我想做的就是

  • 检查第8列中的状态结果(确定或失败)
  • 如果状态为OK,则将源文件移动到另一个文件夹(这样就不会再次上传该文件)。

问题是源文件名后面附加了“ file://”,例如,我似乎无法删除

file://C:\TEMP\file_1.xlsx

需要更改为此

C:\TEMP\file_1.xlsx

我正在使用for / f循环,不确定在%f / f循环中变量%% A的操作是否不同。

@echo off

rem copy the gsutil log file into a temp file and remove the header row using the 'more' command.
more +1 raw_results.log > .\upload_results.log

rem get the source file name (column 1) and the upload result (OK) from column 8
for /f "tokens=1,8 delims=," %%A in (.\upload_results.log) do (
        echo The source file is %%A , the upload status was %%B 

        set line=%%A
        set line=!line:file://:=! >> output2.txt echo !line!
        echo !line!

)

输出是这样的。

The source file is file://C:\TEMP\file_1.xlsx , the upload status was OK
The source file is file://C:\TEMP\file_2.xlsx , the upload status was OK

我希望它可以将更改后的值转储到新文件中,但目前不产生任何结果。 通常,我会使用类似这样的方法将特定字符提取到字符串的末尾,但不适用于For / f循环。

%var:~7%

非常感谢任何指针或其他实现方法。

2 个答案:

答案 0 :(得分:3)

由于要删除的部分似乎固定,因此使用子字符串更加容易。

还使用for /f "skip=1"避免了使用外部命令+1和另一个中间文件的必要。

@echo off & setlocal EnableDelayedExpansion
type NUL>output2.txt
for /f "skip=1 eol=| tokens=1,8 delims=," %%A in (.\upload_results.log) do (
    echo The source file is %%A , the upload status was %%B
    set "line=%%A"
    set "line=!line:~7!"
    echo(!line!>>output2.txt
    echo(!line!
)

答案 1 :(得分:1)

文件名和路径也可以包含一个或多个感叹号。 Windows命令处理器第二次对行set line=%%A进行解析,然后执行启用延迟扩展的命令。请参见How does the Windows Command Interpreter (CMD.EXE) parse scripts?,在此行上,分配给循环变量!的字符串中的每个A都被解释为延迟的扩展环境变量引用的开始或结束。因此,如果文件路径/名称包含一个或多个感叹号,则将循环变量A的字符串分配给环境变量line,并且进行了不必要的修改。

因此,最好避免使用延迟扩展。最快的解决方案是使用第二个 FOR 来完成此任务,以从分配给循环变量file://的字符串中删除A

@echo off
del output2.txt 2>nul
for /F "skip=1 tokens=1,8 delims=," %%A in (upload_results.log) do (
    echo The source file is %%A , the upload status was %%B.
    for /F "tokens=1* delims=/" %%C in ("%%~A") do echo %%D>>output2.txt
)

如果没有循环内的第一个echo命令行,甚至更快:

@echo off
(for /F "skip=1 delims=," %%A in (upload_results.log) do (
    for /F "tokens=1* delims=/" %%B in ("%%~A") do echo %%C
))>output2.txt

第二种解决方案也可以编写为单个命令行:

@(for /F "skip=1 delims=," %%A in (upload_results.log) do @for /F "tokens=1* delims=/" %%B in ("%%~A") do @echo %%C)>output2.txt

所有解决方案都执行以下操作:

外部 FOR 处理ANSI(每个字符固定一个字节)或UTF-8(每个字符固定一到四个字节)编码的文本 file upload_results.log行逐行跳过第一行,而忽略总是空的行和以分号开头的行(在此不会出现)。

通过将第一个逗号分隔的字符串分配给指定的循环变量A,在每次出现一个或多个逗号时将该行拆分为子字符串(令牌)。第一种解决方案还根据ASCII table将第八个逗号分隔的字符串分配给下一个循环变量B

内部 FOR 使用A作为字符串定界符来处理分配给循环变量/字符串,以分配给指定的循环变量{ {1}},然后根据ASCII表转到下一个循环变量,即在第一个正斜杠序列之后的字符串的其余部分,即完整的合格文件名。

使用命令file:输出完整的合格文件名,并将其直接附加到文件echo(第一个解决方案)或首先附加到内存缓冲区,该缓冲区最后立即写入文件{{1} }覆盖当前目录中该文件名可能已经存在的文件。

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • output2.txt
  • output2.txt
  • del /?

有关重定向echo /?for /?>的解释,另请参阅Microsoft关于Using command redirection operators的文章