在.text文件中搜索单词并将几行写入新的.txt文件

时间:2015-03-28 15:47:19

标签: powershell batch-file text

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

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

ITEM
name TICKY
title nice coffe drink
type DRINK
ITEM
name APPLE
title sweet tasty apple
type FRUIT
ITEM
name JUICE
title nice tasty drink
type DRINK
ITEM
name ORANG
title niice nice orange
type FRUIT
ITEM
name CHERY
title nutritious rich fruit
type FRUIT

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

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

APPLE
ORANG
CHERY

这是我的编码(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
}

这将按照以下

提取第二个顶行
name APPLE
name ORANG
name CHERY

以下编码(.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
)

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

ITEM
p_date 10/03/15
pt_time 11:29:40:00
title nice coffe drink
name TICKY
stock yes
end
ITEM
p_date 10/03/15
pt_time 11:29:40:00
title sweet tasty apple
name APPLE
stock yes
end
ITEM
p_date 10/03/15
pt_time 11:29:40:00
title nice tasty drink
name JUICE
stock yes
end
ITEM
p_date 10/03/15
pt_time 11:29:40:00
title niice nice orange
name ORANG
stock yes
end
ITEM
p_date 10/03/15
pt_time 11:29:40:00
title nutritious rich fruit
name CHERY
stock yes
end

我必须在list.txt中搜索来自B.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中最好。

4 个答案:

答案 0 :(得分:0)

你走了。我必须做一些创造性的工作才能使这一切融合在一起。例如,我首先在B.txt中搜索与.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这个词。事实证明,你可以通过使用-Co​​ntext来告诉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

答案 1 :(得分:0)

纯批次解决方案:

@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

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

答案 2 :(得分:0)

下面的批处理文件应该运行得很快,因为它只使用内部命令,但文件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

答案 3 :(得分:0)

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

  • 禁用延迟扩展的解决方案;
  • 没有辅助文件的解决方案;
  • 输出到类似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"

==>