【问题标题】:Batch file: Find string in file and write char to beginning of line批处理文件:在文件中查找字符串并将字符写入行首
【发布时间】:2021-11-25 14:50:39
【问题描述】:

我有一个如下所示的 .csv 文件:

...
;OUTPUT;DISCRETE;VOLTAGE1;;
;OUTPUT;DISCRETE;VOLTAGE2;;
...

现在我想在这个 .csv 文件中搜索字符串,例如“VOLTAGE1”,如果找到,将“#”写到找到搜索字符串的行的开头。

因此,批处理脚本完成后 .csv 文件应如下所示:

...
#;OUTPUT;DISCRETE;VOLTAGE1;;
;OUTPUT;DISCRETE;VOLTAGE2;;
...

我已经找到了如何在文件中搜索字符串的方法,但我不知道如何在 for 循环的“do”部分中将“#”写到行首。那么我该怎么做呢?

到目前为止我的代码:

@echo off
setlocal
for /F "tokens=1* delims=;" %%a in ('findstr /I "VOLTAGE1" file.csv') do <write # to beginning of line>
endlocal

EDIT1:应对原始 .csv 文件进行更改。

所以最后每行包含一个搜索字符串应该在多次调用脚本后以 # 开头

EDIT2:我根据自己的需要调整了 Thor 的代码,但问题是脚本速度很慢。完成 1200 行的 excludes_signals.txt 和 1860 行的 csv 文件大约需要 8 分钟。 excludes_signals.txt 包含所有在 csv 文件中应以“#”开头的信号名称。您知道如何提高脚本的性能吗?

这是我当前的代码:

$base_path = $args[0]
$csv_path = $base_path + "\comms\comms.csv"
foreach($line in Get-Content .\exclude_signals.txt) {
    Import-Csv -Delimiter ';' -Header a,b,c,d,e,f,g,h,i -Path 
    $csv_path |
    ForEach-Object { if ($_.e -like $line) { $_.a = "#" } $_ } |
    ConvertTo-Csv -Delimiter ';' -NoTypeInformation                 |
    Select-Object -skip 1                                           |
    ForEach-Object { $_ -replace '"','' } > mtad_comms.csv
    Remove-Item -Path "$base_path\mtad_comms\mtad_comms.csv"
    Move-Item  -Path .\comms.csv -Destination 
    "$base_path\comms\" -Force
}

EDIT3:我认为性能低下的主要原因是

ForEach-Object { if ($_.e -like $line) { $_.a = "#" } $_ } |

也许Select-String 比将文件的每一行与搜索字符串进行比较更好。如果Select-String 匹配,我只是不知道如何编辑带有{ $_.a = "#" } 的行。

【问题讨论】:

    标签: windows powershell csv batch-file


    【解决方案1】:

    powershell 是一个选项吗?例如:

    ipcsv -d ';' -h a,b,c,d,e,f -pa infile.csv          |
    % { if ($_.d -like "voltage1") { $_.a = "#" }; $_ } |
    ConvertTo-Csv -d ';' -nti | select -skip 1          |
    % { $_ -replace '"','' }
    

    或不打高尔夫球:

    Import-Csv -Delimiter ';' -Header a,b,c,d,e,f -Path infile.csv  |
    ForEach-Object { if ($_.d -like "voltage1") { $_.a = "#" } $_ } |
    ConvertTo-Csv -Delimiter ';' -NoTypeInformation                 |
    Select-Object -skip 1                                           |
    ForEach-Object { $_ -replace '"','' }
    

    输出:

    #;OUTPUT;DISCRETE;VOLTAGE1;;
    ;OUTPUT;DISCRETE;VOLTAGE2;;
    

    【讨论】:

    • 只是为了感兴趣,我尝试了您的解决方案,它确实有效。但是输出不是针对原始 .csv 文件(您的解决方案中的 infile.csv),它只出现在输出窗口中。我编辑了我的问题以更准确。
    • @Gora:您无法进行就地编辑,因此您需要将输出保存到文件中,即将其重定向到输出文件。然后用新文件覆盖旧文件
    • 我根据我的需要调整了你的代码,而且速度很慢。知道如何提高性能吗?请。请参阅我的原始问题中的 EDIT2。
    • @Gora:如果你想要效率,你可能需要切换工具,我建议awk 例如:awk -F';' -v OFS=';' '$4 == \"VOLTAGE1\" { $1 = \"#\" } 1' .\infile.csv
    • 我认为性能低下的主要原因是ForEach-Object { if ($_.e -like $line) { $_.a = "#" } $_ } |。也许Select-String 会比将文件的每一行与搜索字符串进行比较更好。如果Select-String 匹配,我只是不知道如何编辑带有{ $_.a = "#" } 的行。
    【解决方案2】:
    @echo off
    setlocal EnableDelayedExpansion
    
    rem %1 is full file name
    rem %2 is search string
    
    set "n="
    for /F "delims=:" %%n in ('findstr /N "%~2" %1') do set /A "n=%%n-1"
    if not defined n goto :EOF
    
    < %1 (
    
    rem Copy N-1 lines
    for /L %%i in (1,1,%n%) do set /P "line=" & echo !line!
    
    rem Modify target line
    set /P "line=" & echo #!line!
    
    rem Copy the rest
    findstr "^" 2>NUL
    
    ) > output.csv
    
    move /Y output.csv %1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-17
      • 2023-03-29
      • 1970-01-01
      • 2011-10-23
      • 2021-02-24
      • 1970-01-01
      • 2016-02-25
      • 1970-01-01
      相关资源
      最近更新 更多