【问题标题】:Seach for a word in a .txt files and write few lines into a new .txt file在 .text 文件中搜索单词并将几行写入新的 .txt 文件
【发布时间】:2015-03-29 05:54:22
【问题描述】:

请帮助我创建一个脚本来执行如下所述的任务。

我有 2 个文件,A.txtB.txtA.txt 的内容如下所示

物品 名字TICKY 标题不错的咖啡饮料 输入饮料 物品 名称苹果 标题 甜 美味 苹果 类型水果 物品 名称果汁 标题好喝的饮料 输入饮料 物品 名字猩猩 标题不错不错橙色 类型水果 物品 名称奇瑞 标题 营养丰富的水果 类型水果

现在我需要在A.txt 中搜索单词"FRUIT" 并将"FRUIT" 顶部的第二行复制到一个名为list.txt 的新文件中。

但我只需要水果的名称,list.txt 应该如下所示。

苹果 猩猩 奇瑞

这是我执行此操作的编码(powershell)...

$source = "C:\temp\A.txt"
$destination = "C:\temp\list.txt"
$hits = select-string -Path $source -SimpleMatch "type FRUIT" -CaseSensitive
$filecontents = get-content $source
foreach($hit in $hits)
{
    $filecontents[$hit.linenumber-3]| out-file -append $destination
    "" |out-file -append $destination
}

这将提取下面的第二行

名称苹果 名字猩猩 名称奇瑞

下面的编码(.bat)将删除单词"name"

@echo off
setlocal enabledelayedexpansion

del list2.txt
for /f "tokens=*" %%a in (C:\temp\list.txt) do (
  set line=%%a
  set chars=!line:~-13,13!
  echo !chars! >> list2.txt
)

作为第二阶段,现在我需要在B.txtlist.txt 文件(APPLE,ORANG,CHERY)中搜索单词,如下所示。

物品 p_date 10/03/15 pt_time 11:29:40:00 标题不错的咖啡饮料 名字TICKY 有库存 结尾 物品 p_date 10/03/15 pt_time 11:29:40:00 标题 甜 美味 苹果 名称苹果 有库存 结尾 物品 p_date 10/03/15 pt_time 11:29:40:00 标题好喝的饮料 名称果汁 有库存 结尾 物品 p_date 10/03/15 pt_time 11:29:40:00 标题不错不错橙色 名字猩猩 有库存 结尾 物品 p_date 10/03/15 pt_time 11:29:40:00 标题 营养丰富的水果 名称奇瑞 有库存 结尾

我必须在B.txt 中搜索来自list.txt 的单词并提取顶部的3 行并将其相应地写入一个名为done.txt 的新文件中。下面是我的编码(powershell)。

$source = "C:\temp\B.txt"
$destination = "C:\temp\done.txt"
$patterns = Get-Content c:\temp\list2.txt | Where-Object{$_}
$results = Select-String c:\temp\done.txt -Pattern $patterns -SimpleMatch
$results.Line | ForEach-Object{"$_`r`n"} | Set-Content c:\temp\done.txt
foreach($hit in $hits)
{
    $filecontents[$hit.linenumber-4]| out-file -append $destination
    $filecontents[$hit.linenumber-3]| out-file -append $destination
    $filecontents[$hit.linenumber-2]| out-file -append $destination
    $filecontents[$hit.linenumber-1]| out-file -append $destination
    "" |out-file -append $destination
}

我设法为此开发了编码。但我需要 3 个脚本文件(2 个 powershell 和 1 个批处理)来完成此操作。

请帮助我在一个脚本中完成此任务。最好是 .vbs 或 .bat 格式。

【问题讨论】:

  • 我认为你需要退后几步,再看一遍并重新考虑。如果您要返回以匹配其他“name FRUIT”字符串,则从“name FRUIT”字符串中提取水果名称似乎毫无意义。你有一个完全匹配你正在寻找的开始。此外,您说您需要 2 个 Powershell 脚本,然后说“最好在 .vbs 或 .bat 中”。我认为没有人会愿意在周六的大部分时间里试图跳过那个圈子,

标签: powershell batch-file text


【解决方案1】:

给你。我必须做一些创造性的工作才能使这一切融合在一起。例如,我不是两个脚本,而是首先在 B.txt 中搜索与我们在 A.txt 中的名称相匹配的水果名称,然后构建一个自定义对象数组,以便于搜索,如下所示:

    #Mark the word ITEM as the start of each record
$BHits = Select-String -Path $BSource -SimpleMatch "ITEM" -CaseSensitive -Context 5

#Make an empty array to hold our PowerShell Objects
$fruitMatches = @()
$output = @()

#Make $FruitMatches contain our purchase records
ForEach ($bhit in $BHits){
    $fruitMatches += [pscustomobject]@{Fruit=$BHit.Context.PostContext[3].Replace("name ",'');
        Date=$BHit.Context.PostContext[0].Replace('p_date ','');
        Time=$BHit.Context.PostContext[1].Replace('pt_time ','')}
}

我为什么要这么做?好吧,首先,您想从 Select-String 输出中删除单词 Name。事实证明,您可以很容易地做到这一点,方法是使用 -Context 告诉 PowerShell 抓取一定数量的行以及匹配项,并且选择您想要的特定行就像索引对象一样简单,如下所示:

#In one line, find the word type Fruit, and remove the word 'name'
($hit.Context.PreContext[0].Replace('name','').Trim()) 
>Cherry

现在知道,当您看到那长串 $hit.Context... 时,它将解析为只是水果的名称。好吧,我们费心制作自定义对象的原因是,我可以像这样轻松地搜索匹配的对象:

ForEach ($hit in $hits){

    $fruitMatches | ? Fruit -eq ($hit.Context.PreContext[0].Replace('name','').Trim()) 
    }

这将为我们提供以下输出:

Fruit                                  Date                                   Time                                 
-----                                  ----                                   ----                                 
APPLE                                  10/03/15                               11:29:40:00                          
ORANG                                  10/03/15                               11:29:40:00                          
CHERY                                  10/03/15                               11:29:40:00 

从现在开始,我只是创建了几个空数组来保存结果,并通过使用重定向字符> 转储输出来结束整个事情。

这用一个脚本回答了您的整个前提。如果您对它的工作原理有任何疑问,请告诉我。

已完成答案

$source = "T:\A.txt"
$BSource = "t:\b.txt"
$destination = "T:\done.txt"


#Mark the word ITEM as the start of each record
$BHits = Select-String -Path $BSource -SimpleMatch "ITEM" -CaseSensitive -Context 5

#Make an empty array to hold our PowerShell Objects
$fruitMatches = @()
$output = @()

#Make $FruitMatches contain our purchase records
ForEach ($bhit in $BHits){
    $fruitMatches += [pscustomobject]@{Fruit=$BHit.Context.PostContext[3].Replace("name ",'');
        Date=$BHit.Context.PostContext[0].Replace('p_date ','');
        Time=$BHit.Context.PostContext[1].Replace('pt_time ','')}
}

#Resolve our Hits, looking in file A.txt for the line type FRUIT
$hits = select-string -Path $source -SimpleMatch "type FRUIT" -CaseSensitive -Context 2
ForEach ($hit in $hits){

    $output += $fruitMatches | ? Fruit -eq ($hit.Context.PreContext[0].Replace('name','').Trim()) 
    }


$output > $destination
Write-Output "Checking $destination for matches"
Get-content $destination

【讨论】:

    【解决方案2】:

    纯批处理:

    @echo off
    setlocal enabledelayedexpansion
    REM create temporary numbered files:
    findstr /n "^" a.txt >tempA.txt
    findstr /n "^" b.txt >tempB.txt
    
    (
      REM search for "type FRUIT" and fetch (linenumber-2)
      for /f "tokens=1 delims=: " %%a in ('findstr /c:"type FRUIT" tempA.txt') do (
        set /a line=%%a-2
    
        REM get content of this line:
        for /f "tokens=1,3 delims=: " %%d in ('findstr /b "!line!:" tempA.txt') do (
    
          REM get Fruit-linenumbers of B.txt:
          for /f "tokens=1 delims=:" %%g in ('findstr /c:"name %%e" tempB.txt') do (
            set /a line3=%%g-3
            set /a line2=%%g-2
            set /a line1=%%g-1      
    
            REM get the desired three lines from B.txt      
            for /f "tokens=1,* delims=:" %%j in ('findstr /b "!line3!: !line2!: !line1!: " tempB.txt') do (
              echo %%k
            )
          )
        )
        echo.
      )
    )>done.txt
    del temp?.txt
    type done.txt
    

    基本技巧是,将行号添加到文件中,查找搜索字符串并计算所需行的行号。

    【讨论】:

      【解决方案3】:

      下面的批处理文件应该运行得很快,因为它只使用内部命令,但它被限制为文件 A.txt 中最多 1364 个水果。如果你有更多,可以修改该方法以使用辅助文件并使用findstr处理它,但在这种情况下程序会运行得更慢。

      @echo off
      setlocal EnableDelayedExpansion
      
      rem Create list of fruit names from A.txt
      set "list=/"
      set "type="
      for /F "tokens=1,2" %%a in (A.txt) do (
         set "%%a=%%b"
         if "!type!" equ "FRUIT" (
            set "list=!list!!name!/"
            set "type="
         )
      )
      
      rem Extract 3 lines from B.txt
      set "name="
      (for /F "tokens=1*" %%a in (B.txt) do (
         set "%%a=%%b"
         for %%c in (!name!) do (
            if "!list:/%%c/=!" neq "%list%" (
               echo p_date !p_date!
               echo pt_time !pt_time!
               echo title !title!
               echo/
               set "name="
            )
         )
      )) > done.txt
      

      【讨论】:

        【解决方案4】:

        具有下一个关键思想和/或限制的纯批处理解决方案:

        • 禁用延迟扩展的解决方案;
        • 没有辅助文件的解决方案;
        • 输出到类似 CSV 的文件;
        • 如果在没有任何参数的情况下调用,则可以更快地处理具有特定水果(库存列表)的独特外观的B.txt 文件;在这种情况下,输出特定水果的第一次出现;
        • 如果使用非空参数调用,则能够处理 B.txt 文件(销售单列表)中特定水果的多次出现,请参见下面的输出;
        • A.txt 文件中的不同水果数量没有限制。可笑的优势,当然也很难想到甚至列举超过 1364 种水果 :))
        • 可能比 Stephan 和 Aacini 的解决方案慢,尤其是在输入文件不断增长的情况下。

        脚本:

        @ECHO OFF >NUL
        SETLOCAL enableextensions disabledelayedexpansion
        set "multipleFruitInBfile=%~1"
        echo "name";"title";"p_date";"pt_time"> 29319122done.txt
        for /F "tokens=1*" %%G in (29319122A.txt) do (
            set "A%%G=%%H"
            if /I "A%%G"=="Atype" if /I "%%H"=="FRUIT" (
                call :forFruit
          )
        )
        ENDLOCAL
        type 29319122done.txt
        goto :eof
        
        :forFruit
        SETLOCAL
        for /F "tokens=1*" %%g in (29319122B.txt) do (
            set "%%g=%%h"
            if "%%g"=="name" if "%%h"=="%Aname%" (
                call :forEcho 
                if "%multipleFruitInBfile%"=="" goto :eof
            )
        )
        ENDLOCAL
        goto :eof
        
        :forEcho
        echo "%name%";"%title%";"%p_date%";"%pt_time%">> 29319122done.txt
        goto :eof
        

        输出(B.txt 文件中的 ORANG 记录加倍):

        ==>D:\bat\29319122.bat
        "name";"title";"p_date";"pt_time"
        "APPLE";"sweet tasty apple";"10/03/15";"11:29:41:00"
        "ORANG";"niice nice orange";"10/03/15";"11:29:43:00"
        "CHERY";"nutritious rich fruit";"10/03/15";"11:29:44:00"
        
        ==>D:\bat\29319122.bat 1
        "name";"title";"p_date";"pt_time"
        "APPLE";"sweet tasty apple";"10/03/15";"11:29:41:00"
        "ORANG";"niice nice orange";"10/03/15";"11:29:43:00"
        "ORANG";"niice nice orange";"11/03/15";"11:29:45:00"
        "CHERY";"nutritious rich fruit";"10/03/15";"11:29:44:00"
        
        ==>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-06-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多