AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 76934973
Accepted
Kriston
Kriston
Asked: 2023-08-19 19:55:38 +0800 CST2023-08-19 19:55:38 +0800 CST 2023-08-19 19:55:38 +0800 CST

BAT 文件 - 根据文件内容重命名多个 .csv 文件

  • 772

我有多个分号分隔的.csv文件:

sample.csv
sample1.csv
...etc.

每个都有两个记录、一个标题和数据。

示例sample.csv:

record-type-cd;record-creation-dt;product-bank-swift-cd;term-deposit-id;saving-global-servicing-bank-name;product-bank-name;customer-account-iban;customer-id;term-deposit-reference;customer-id;term-deposit-reference;payin-iban;payout-iban
ACC;2023-08-18;BBLUK;ABCDEFG-3;check24toprovide;Testcase;DE335666666666666;ABCDEFG-1;2800123456720890;ABCDEFG-1;2800123456720890;DE66110000007000110910000;BE66110000007000110910100

对于每个文件,我需要根据其数据记录的第一、第二和第四字段重命名每个文件。

对于上面的例子,那就是:

ACC2023-08-18ABCDEFG-3.csv

当我使用以下代码时,它给出delimiter__.csv新名称:

@echo off
setlocal enabledelayedexpansion

REM Specify the input .csv file name and path
set "inputFile=sample.csv"

REM Read the 2nd line of the .csv file
set /a lineNumber=0
for /f "usebackq skip=1 delims=" %%a in ("%inputFile%") do (
    set /a lineNumber+=1
    if !lineNumber! equ 1 (
        set "line=%%a"
        goto processLine
    )
)

:processLine
REM Set the delimiter used in the .csv file
set "delimiter=;"

REM Split the line into separate columns
set "colIndex=0"
for %%b in ("%line:%delimiter%=" "%") do (
    set /a colIndex+=1
    set "col!colIndex!=%%~b"
)

REM Get the required columns from the line
set "newFileName=!col1!_!col2!_!col4!.csv"

REM Rename the input file
ren "%inputFile%" "!newFileName!"

echo File renamed to: !newFileName!
pause
csv
  • 1 1 个回答
  • 25 Views

1 个回答

  • Voted
  1. Best Answer
    Mofi
    2023-08-19T21:43:50+08:002023-08-19T21:43:50+08:00

    可以用于此任务:

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    (for /F "eol=| delims=" %%B in ('dir *.csv /A-D /B 2^>nul') do call :ReadData "%%B") & goto EndBatch
    :ReadData
    for /F "usebackq skip=1 tokens=1,2,4 delims=;" %%G in (%1) do set "NewFileName=%%G%%H%%I.csv" & goto RenameFile
    :RenameFile
    if /I not %1 == "%NewFileName%" ren %1 "%NewFileName%"
    goto :EOF
    :EndBatch
    endlocal
    

    前两个命令行完全定义了所需的执行环境

    • 关闭命令回显模式,
    • 启用FOR循环、IF条件和goto :EOF,所需的命令扩展
    • 禁用延迟变量扩展以处理正确的!文件名中的 CSV 文件。

    接下来在后台执行:%ComSpec% /c dir *.csv /A-D /B 2>nul
    启动运行%SystemRoot%\System32\cmd.exe其内部命令DIR

    • 由于选项而在当前目录中仅搜索文件/A-D(属性而不是目录)
    • 其中长文件名或短文件名通过通配符模式匹配*.csv
    • 由于选项,仅以裸格式输出 CSV 文件名/B。

    通过使用将其重定向到设备NUL,可以抑制当前目录上不包含 CSV 文件的错误消息输出2>nul。重定向运算符>必须在批处理文件的FOR命令行中转义,才能通过处理批处理文件将其解释为文字字符,而不是解释为重定向cmd.exe运算符。

    处理批处理文件的Windows命令处理器实例捕获在后台执行的命令进程的输出,并在启动cmd.exe完成并自行关闭后处理捕获的行。cmd.exe捕获的输出是现在加载到处理批处理文件的内存中的文件名列表。

    在执行文件重命名之前,必须将 CSV 文件的所有文件名加载到命令进程的内存中,这一点很重要,否则可能会发生简单的循环,例如某些 CSV 文件根本不被处理,而其他文件则被for %%B in (*.csv) do处理多次。标准FOR*.csv循环指示文件系统在每次迭代时返回与通配符模式匹配的下一个文件名,这对于在每次执行命令REN后与文件系统中与更改匹配的文件系统中的文件名列表相同的目录中的文件进行重命名是有问题的。

    使用FOR /F选项eol=|,将 CSV 文件在文件名开头可以具有的delims=默认行尾字符更改为文件名不能包含的垂直线,以及默认水平制表符和普通分隔符列表;空格到空的分隔符列表。这两个选项可确保进一步处理时不会忽略任何 CSV 文件名,并将完整的文件名分配给循环变量B,即使是类似 ; sample file with leading space and semicolon.csv.

    对于每个文件名,调用子例程ReadData,将文件名传递给包含在其中的子例程,"以处理包含空格或这些字符之一的正确文件名&()[]{}^=;!'+,`~。

    整个FOR循环包含在一个命令块中,该命令块从(行首开始,以 after 匹配结束,)用于"%%B"在同一命令行上使用无条件命令运算符&,并在同一命令行上指定goto EndBatch在重命名所有 CSV 文件后继续批处理文件处理位于标签线下方EndBatch。这可以避免重命名所有 CSV 文件后陷入子例程。

    使用子例程重命名数百甚至数千个 CSV 文件的效率非常低。但是批处理文件的处理使用所使用的代码进行了一些优化,因为标签总是立即在批处理文件的下一行上ReadData找到。cmd.exe这减少了文件重命名任务的文件系统访问。

    在子例程中ReadData,又使用了一个FOR /F循环,该循环打开 CSV 文件,跳过 CSV 文件顶部的标题行,读取第二行,使用分号作为分隔符将其拆分为子字符串,并分配第一个、第二个和第四个分号分隔循环变量G,H和 的字符串I。

    注 1: _ 第二行不能以分号开头,即第一个数据列中有空值。

    注 2: _ 第二行也不应该有空的第二个、第三个或第四个数据值,因为FOR /F解释;;为一个分隔符而不是两个分隔符。

    换句话说,对于前四个数据列,第二个数据行必须始终具有四个非空值。

    使用第一、第二和第四数据值的 CSV 文件的新文件名被分配给环境变量,NewFileName并且通过在同一命令行上在无条件命令运算符之后另外使用退出循环的&命令来退出 CSV 文件的处理goto RenameFile即使 CSV 文件有多于两行。这也会导致关闭打开的 CSV 文件,cmd.exe这在这里很重要,因为 CSV 文件应该使用下一个命令行重命名,而这在任何进程(包括cmd.exe处理批处理文件)仍然打开的情况下是不可能的。

    (在以匹配开头和结尾的命令块内不可能存在标签),这就是使用子例程的原因,该子例程goto RenameFile可用于退出循环并使用标签下方的行继续批处理文件处理RenameFile。

    接下来,如果当前 CSV 文件还没有所需的文件名,则通过不区分大小写的字符串比较进行检查。这种情况使得可以在同一目录中多次运行批处理文件,而不会在当前目录中的一个或多个 CSV 文件已经具有所需的文件名时显示错误消息。

    否则,如果当前文件名不等于新文件名,则当前 CSV 文件将重命名为其新名称。如果当前 CSV 文件由另一个进程打开,或者当前目录中已存在与当前文件的新文件名同名的文件/文件夹,则文件重命名可能会失败。在这种情况下会输出一条错误消息。

    子例程退出,goto :EOF导致批处理文件处理返回到第一个FOR /F循环,该循环分别处理下一个捕获的行和 CSV 文件名。

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

    • dir /?
    • echo /?
    • endlocal /?
    • for /?
    • goto /?
    • if /?
    • ren /?
    • setlocal /?

    也可以看看:

    • Windows 命令解释器 (CMD.EXE) 如何解析脚本?
    • 为什么在cmd中使用“set var = text”命令后没有“echo %var%”字符串输出?
    • `for` 或 `for /R` 在什么时候枚举目录(树)?
    • 相当于Windows批处理文件中的NEQ、LSS、GTR等符号
    • 使用 Windows 批处理文件的单行多个命令
    • GOTO :EOF 返回到哪里?
    • 1

相关问题

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    使用 <font color="#xxx"> 突出显示 html 中的代码

    • 2 个回答
  • Marko Smith

    为什么在传递 {} 时重载解析更喜欢 std::nullptr_t 而不是类?

    • 1 个回答
  • Marko Smith

    您可以使用花括号初始化列表作为(默认)模板参数吗?

    • 2 个回答
  • Marko Smith

    为什么列表推导式在内部创建一个函数?

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 个回答
  • Marko Smith

    为什么 'char -> int' 是提升,而 'char -> Short' 是转换(但不是提升)?

    • 4 个回答
  • Marko Smith

    为什么库中不调用全局变量的构造函数?

    • 1 个回答
  • Marko Smith

    std::common_reference_with 在元组上的行为不一致。哪个是对的?

    • 1 个回答
  • Marko Smith

    C++17 中 std::byte 只能按位运算?

    • 1 个回答
  • Martin Hope
    fbrereto 为什么在传递 {} 时重载解析更喜欢 std::nullptr_t 而不是类? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 您可以使用花括号初始化列表作为(默认)模板参数吗? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi 为什么列表推导式在内部创建一个函数? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A fmt 格式 %H:%M:%S 不带小数 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python C++20 的 std::views::filter 未正确过滤视图 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute 为什么 'char -> int' 是提升,而 'char -> Short' 是转换(但不是提升)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa 为什么库中不调用全局变量的构造函数? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis std::common_reference_with 在元组上的行为不一致。哪个是对的? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev 为什么编译器在这里错过矢量化? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan C++17 中 std::byte 只能按位运算? 2023-08-17 17:13:58 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve