批处理文件读取未使用的第一行文本,并将其标记为已使用

4
我需要在Windows批处理文件中读取文本文件的第一行,并将其传递给变量,并标记该名称\行已使用。示例文本文件如下:
apple pear orange
脚本应从“apple”开始,将“apple”传递给变量以便稍后在脚本中使用(我知道如何做到这一点),然后将该行写回已读取和Apple的“&”作为标记符表示它已被使用。
文件现在看起来像:
&apple pear orange
下次运行批处理文件时,它会获取“pear”,将其传递给变量并用“&”标记它,使其看起来像:“
&apple &pear orange
我尝试查找“&”并尝试移动到下一行,但是经过大约12个小时的尝试失败了。这是我迄今为止得到的内容……不多:
for /f "tokens=1" %l in ('name.txt') do (Find /v "&" /v "^---- ^$") (For /F %n in (%l) do (set NewName=%n))
2个回答

7

在运行此命令时,会逐行修改the.file中的每一行;

@echo off
setlocal enabledelayedexpansion
type nul > the.file.temp
set last=
for /F "tokens=*" %%A in (the.file) do (
    set line=%%A
    if "!line:~0,1!" neq "&" if "!last!" equ "" (
        set last=!line!
        set line=^&!line!
    )
    echo !line! >> the.file.temp
)

echo last value is !last!
type the.file.temp > the.file

如果一行不以&开头,且变量last为空,则将该行放入last并修改line为以&开头。无论何时都将line追加到临时文件中,在完成后重命名。


1
非常抱歉,但这超出了我的理解范围,我无法理解它。请问要将值(例如apple)放入变量中吗?如果是的话,应该放在哪个变量里?如果不是,我无法确定在脚本中放置的位置。谢谢。 - idarryl
1
在最后一行之后,值为!last!。例如:echo value is '!last!' - Alex K.
+1 - 这个解决方案运行良好,但相对较慢。请参考我的答案获取更快的解决方案。 - dbenham

4

Alex K.提供的答案在大多数情况下可能都很好。(我赞同。)

然而,它会破坏任何包含!的文本。可以通过在循环内切换延迟扩展来解决这个限制。

对于大多数大小合理的文件,该解决方案可能足够快。但是,对于大型文件,FOR循环可能变得非常缓慢。

我测试了一个包含2817行的190kb文件,Alex K.的解决方案需要20秒才能运行一次。

以下是一种完全不使用任何循环的完全不同的解决方案,可以在0.07秒内处理相同的190kb文件-速度快285倍:)

@echo off
setlocal enableDelayedExpansion
set "file=test.txt"
findstr /bv "$ &" "%file%" >"%file%.available"
set "var="
<"%file%.available" set /p "var="
if defined var (
  >"%file%.new" (
    findstr /b "&" "%file%"
    <nul set /p "=&"
    type "%file%.available"
  )
  move /y "%file%.new" "%file%" >nul
)
del "%file%.available"

echo var=!var!


更新:根据评论的要求,这里提供了一份有详细注释的代码版本。

@echo off
setlocal enableDelayedExpansion

:: Define the file to process
set "file=test.txt"

:: Write the unused lines to a temporary "available" file. We don't want any
:: empty lines, so I strip them out here. There are two regex search strings;
:: the first looks for empty lines, the second for lines starting with &.
:: The /v option means only write lines that don't match either search string.
findstr /bv "$ &" "%file%" >"%file%.available"

:: Read the first available line into a variable
set "var="
<"%file%.available" set /p "var="

:: If var defined, then continue, else we are done
if defined var (

  REM Redirect output to a "new" file. It is more efficient to redirect
  REM the entire block once than it is to redirect each command individulally
  >"%file%.new" (

    REM Write the already used lines to the "new" file
    findstr /b "&" "%file%"

    REM Append the & without a new line
    <nul set /p "=&"

    REM Append the unused lines from the "available" file. The first appended
    REM line is marked as used because of the previously written &
    type "%file%.available"
  )

  REM Replace the original file with the "new" content
  move /y "%file%.new" "%file%" >nul
)

:: Delete the temp "available" file
del "%file%.available"

:: Display the result
echo var=!var!

我没有测试过这个,但我刚意识到我可以写一行代码来查找不以字符 & 开头的行。
findstr "^[^&]" "%file%" >"%file%.available"

+1 令人印象深刻!但有点困惑...你能否添加详细的注释来解释正在发生的事情,如何、何时、何地...“老师,我的大脑已经满了,我可以走了吗?” :) - Lizz
哇..从来没有看到批处理行以<符号开头。非常好的注释!希望我能给多个++!! 话说,为什么添加注释要这么久?我的意思是32分钟?你是不是花时间呼吸了?!;-D - Lizz
@Lizz - 其实你碰巧在线遇到了我。我已经看了几个小时的电视了。我刚刚看完了《黄金三镖客》- 经典 :-) - dbenham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接