【问题标题】:Windows Batch file - strip leading charactersWindows 批处理文件 - 去除前导字符
【发布时间】:2019-05-06 06:49:53
【问题描述】:

我有一个批处理文件,它使用 gsutil 工具将一些本地文件复制到谷歌存储区域。 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 或 FAIL)
  • 如果状态正常,则将源文件移动到另一个文件夹(以免再次上传)。

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

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

需要改成这个

C:\TEMP\file_1.xlsx

我正在使用 for /f 循环,我不确定在 for /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%

非常感谢任何指针或不同的方式。

【问题讨论】:

  • 您正在对变量使用延迟扩展,但您没有使用 SETLOCAL 命令启用它。
  • 这要么是您的语法错误,要么是我的错误。 file://: 字符串不存在!你的意思是file://?那么,你的方法就好了!
  • 另外,*text text text text* >> output2.txt echo !line! 是什么意思。你的意思是*text text text text* >> output2.txt && echo !line! 没有echo !line! 在下一行?

标签: windows loops batch-file substring


【解决方案1】:

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

还使用for /f "skip=1" 避免了外部命令more +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!
)

【讨论】:

  • 现在工作正常,感谢您解释我哪里出错了。
【解决方案2】:

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

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

@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(每个字符一到四个字节)编码的文本文件upload_results.log跳过第一行并忽略始终为空行和以分号开头的行,但此处不会出现。

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

内部FOR处理分配给循环变量A字符串,使用/作为字符串分隔符以分配给指定的循环变量file:和下一个循环变量根据 ASCII 表在第一个正斜杠序列之后的字符串的其余部分,这是完整的限定文件名。

使用命令echo 输出完整的限定文件名,并直接附加到文件output2.txt(第一种解决方案)或首先附加到内存缓冲区,最终立即写入文件output2.txt 覆盖可能已经存在的文件在当前目录中具有该文件名的文件。

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

  • del /?
  • echo /?
  • for /?

另请参阅有关 Using command redirection operators 的 Microsoft 文章,了解重定向 >>>2>nul 的说明

【讨论】:

  • 我没有考虑过名称中带有感叹号的文件及其后果。非常感谢您对延迟扩展的见解,应该可以帮助我避免未来的陷阱。
猜你喜欢
  • 1970-01-01
  • 2010-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-13
相关资源
最近更新 更多