如何使用批处理脚本从文本文件中获取唯一字符串

Posted

技术标签:

【中文标题】如何使用批处理脚本从文本文件中获取唯一字符串【英文标题】:how to get a unique string from a text file using Batch script 【发布时间】:2021-06-01 01:25:03 【问题描述】:

我有一个包含以下信息的文本文件:

-host A -P 1
-host A -P 2

-host B -P 1
-host B -P 2
-host B -P 3

-host C -P 1
-host C -P 2

-host A -P 3

现在从批处理脚本中,我想唯一地提取这些主机名。例如,获取我的数组后应该是这样的:[A B C]

我可以通过以下命令获取这些主机名:

setlocal ENABLEDELAYEDEXPANSION
set /A f=0
if exist "%TEXTFILE%" for /F usebackq^ delims^=^ eol^= %%I in (%TEXTFILE%) do for %%J in (%%I) do (
    if /I "%%~J" == "-host" (
        set /A f=1
    ) else (
        if !f!==1 (
            echo %%J
            set /A f=0
        ) 
    )
)

我得到以下输出:

A
A
B
B
B
C
C
A

但我只想要这里唯一的名称。 我们应该如何从文本文件中获取唯一名称?

【问题讨论】:

相关:Batch to remove duplicate rows from text file Gaurav Sahu,我注意到您已返回登录到此站点,但未将提供的任何官方答案标记为已接受。请参阅What should I do when someone answers my question? 了解在这种情况下您可以选择哪些选项,因为没有接受答案的问题不会被本网站视为已回答。 【参考方案1】:
@echo off
setlocal
for /f "tokens=2" %%a in (test.txt) do set "_%%a=."
for /f "delims=_=" %%a in ('set _') do echo %%a

输出:

A
B
C

第一个for 为每个名称设置一个变量(我们不关心内容)。 第二个for 列出了这些变量。为此,所有变量都必须以相同的字符开头,并且没有其他变量可以以该字母开头。 set 命令甚至会按字母顺序为您排序。

@echo off
setlocal enabledelayedexpansion
set "list=["
for /f "tokens=2" %%a in (test.txt) do set "_%%a=."
for /f "delims=_=" %%a in ('set _') do set "list=!list! %%a"
set "list=%list:[ =[%]"
echo %list%

输出:

[A B C]

【讨论】:

它说“环境变量_未定义” 然后它没有读取文件(正确)。 它正在我在问题中发布的代码中正确读取文件。那怎么现在不能读了呢? 文件的编码是什么? @GauravSahu - 你记得用你的文件替换test.txt,对吧?【参考方案2】:

接下来是一个看起来相当复杂的批处理文件,仅为在 Windows 10 上使用而编写。代码仅在该操作系统版本中使用sort 命令的新的但未记录的/unique 选项。 我应该在这里提到sort 命令不区分大小写,因此aA 不是唯一的。

它会尝试获取前导 -host 单词和任何后续 -P* 单词之间的所有修剪内容。我这样做是为了确保仍会捕获包含空格的字符串。主机名中不允许使用空格,因此您不需要这个额外的功能,但是,对于一般用途,它可能对您有用。此外,如果您希望稍后修改它以供其他用途,它目前不会捕获以连字符开头的子字符串,这在主机名中也是不允许的,(您需要修改 findstr 子匹配 @987654329 @ 在线 8 以允许此类字符串)。 最后,如果您不区分大小写的行前导词不是 -host,您可以在行 8 上更改它,如果您的第二个连字符前导词没有'不要以不区分大小写的字符对-P开头,您可以在11行上修改它。

预期的输出应该是一个变量%array%,使用您发布的示例,它应该如下所示:

"A","B","C"

如果您不想使用逗号,请将37 线上的^, 更改为 。此外,如果您不需要封闭的双引号,请将35 上的"%%I" 更改为%%I,将37 上的"!$:~1!" 更改为!$:~1!

它还应该为每个数组索引项创建单独的变量,格式为%array[#]%其中#是索引号,从零开始,(您可以通过在线更改Set "$=-1"来调整它17Set "$=0"array[0] 在线 28array[1])。 使用您发布的示例,当前代码应生成以下内容:

%array[0]% - expanding to string value A
%array[1]% - expanding to string value B
%array[2]% - expanding to string value C

这里是批处理文件示例,请记住将%TEXTFILE% 的值调整为3 行上源文件的完整路径(推荐) 或相对路径:

@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "TEXTFILE=myfile.txt"
Set "$T=%TEMP%\$.lst"
If Not Exist "%TEXTFILE%" GoTo :EOF
For /F "Delims==" %%G In ('"(Set array) 2>NUL"') Do Set "%%G="
(   For /F Delims^=^ EOL^= %%G In ('Type "%TEXTFILE%" ^|
     %SystemRoot%\System32\findstr.exe /RIC:"^-host[ ][ ]*[^-]"') Do (
        Set "$=%%G"
        SetLocal EnableDelayedExpansion
        For /F "Delims=&" %%H In ("!$: -P=&:!") Do (
            EndLocal
            For /F "Tokens=1,*" %%I In ("%%H") Do Echo %%J
        )
    )
) 1>"%$T%"
Set "$=-1"
For /F Delims^=^ EOL^= %%G In (
    '%SystemRoot%\System32\sort.exe /Unique "%$T%" ^& Del "%$T%"'
) Do (
    Set /A $ += 1
    SetLocal EnableDelayedExpansion
    For %%H In (!$!) Do (
        EndLocal
        Set "array[%%H]=%%G"
    )
)
If Not Defined array[0] GoTo :EOF
For /F "Tokens=1,* Delims=]" %%G In ('"(Set array[) 2>NUL"') Do (
    Set "$=%%H"
    SetLocal EnableDelayedExpansion
    If Not Defined array (
        For /F Delims^=^ EOL^= %%I In ("!$:~1!") Do (
            EndLocal
            Set "array="%%I""
        )
    ) Else For /F UseBackQ^ Delims^=^ EOL^= %%I In ('!array!^,"!$:~1!"') Do (
        EndLocal
        Set "array=%%I"
    )
)
For %%G In (TEXTFILE $T $) Do Set "%%G="

Set array & Pause

最后一行只是为了确保您可以看到结果变量及其值。测试后,您可以根据需要将其替换为您自己的代码。

【讨论】:

以上是关于如何使用批处理脚本从文本文件中获取唯一字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何在脚本中获取进程ID

如何逐行读取批处理文件中多余字符的文本文件?允许限制行长。(Windows,批处理脚本)

如何使用bat脚本批处理所有txt文本文件中的每一行开头添加一个指定字符

如何在该行某处某处的某一行中的特定字符串之后从文本文件中获取一个数字?

bash 文本处理以删除 ascii 并从结果中获取唯一行

如何通过文件处理从给定的数据框列中获取唯一对?