使用批处理脚本(如果需要,可以使用gawk)根据特定字段从CSV文件中删除重复项的更有效方法是什么?

1cklez4t  于 2023-06-03  发布在  其他
关注(0)|答案(2)|浏览(121)

我有两个csv文档,其中包含由GAM生成的Google Drive中的源和目标文件列表。一个名为copytoarchive.csv,列出了源代码中的所有相关文件。另一个是alreadyinarchive.csv,列出了目标中已经存在的所有相关文件。
Google云端硬盘的工作方式是为每个文件分配一个UID,而不管其名称如何。csv文件列表在一列中显示文件UID,在另一列中显示文件名。
以下是copytoarchive.csv的示例:

Owner,id,name,Parent
user@domain.com,1gyKqu_P0h3j1Vn-6EwUv_99q,PreschoolExampleLessonName-20230504_050216-Meeting Recording.mp4,1b-U8XU0jYVFCggoEH9E9wqUm
user@domain.com,14-sg-qSnn5GDAuftANdLxDXp,OneonOneExampleLessonName-20230510_043228-Meeting Recording.mp4,1TtaABRvoki4gNuyqRrlyTfzj
user@domain.com,1L9mQBJ6d3DIPbiIEyV7akArV,OtherYearLevelExampleLessonName-20230510_033024-Meeting Recording.mp4,1CdiBgePlVqPvtcEp83DmcUrotr
user@domain.com,1oHaFzLF_KcgVX-hZn5etBka9,TeacherTrainingLesson-20230510_000950-Meeting Recording.mp4,1QusVD-a9U16I-0GTP1t-Vd9Ez
user@domain.com,1_ewCEh37sZYpqZlr3TC8u2Yl,ExampleStaffMeeting-20230509_045403-Meeting Recording.mp4,1tOb7xV5OCMMebn2ab2KdXGvc
user@domain.com,1SyXjINXttrb3VKvpbjpm1y-V,ExampleLessonName-20230503_052304-Meeting Recording.mp4,13g_fYh9HYtnDtd4psHEZi

以下是alreadyinarchive.csv的外观:

Owner,id,name,Parent
user@domain.com,1Zlnhqf6fSxTRT2JEmQS91cCX,PreschoolExampleLessonName-20230504_050216-Meeting Recording.mp4,1CdiBgePlVqPvtcEp83DmcUro
user@domain.com,1Lg2W0w8YGJytSgJl2JblBly3,OtherYearLevelExampleLessonName-20230510_033024-Meeting Recording.mp4,1TtaABRvoki4gNuyqRrlyTfzj
user@domain.com,1Q_K0D1RgZlz-LMlDUVrV0gGi,ParentTrainingLesson-20230510_000950-Meeting Recording.mp4,1b-U8XU0jYVFCggoEH9E9wq
user@domain.com,1LIrRoTGtADjQRg9IRmIlJ3oV,ExampleStaffMeeting-20230509_045403-Meeting Recording.mp4,1xVuHbE3pcWN1l7X109qTsIYZK
user@domain.com,1OHkH9Cg7i2-O-ZHXBr4wIYGZ,OneonOneExampleLessonName-20230510_043228-Meeting Recording.mp4,1U7Y2Xh4Qi3atCcVL262
user@domain.com,1jZsXB5TT0H0TRrvvZu5A3N1S,DifferentLessonName-20230503_052614-Meeting Recording.mp4,1eVS3QF_Sk_6fQkwF8PvTKQf

“所有者”(Owner)和“父项”(Parent)字段中的数据与批处理文件的此部分无关。

如何在csv中搜索文件名字段(字段3)中的重复项,然后删除整个记录或仅输出字段3中不包含重复项的记录到新文件?

例如:
1.请注意,第一个非头记录copytoarchive.csv的文件名与第一个非头记录alreadyinarchive.csv的文件名相匹配,即使UID不同。这将被标记为重复。
1.还要注意,第二个非头记录copytoarchive.csv中的文件名与第五个非头记录alreadyinarchive.csv中的文件名相匹配,尽管UID不同。这也将被标记为重复。
1.此外,请注意,尽管copytoarchive.csvTeacherTrainingLesson...(第4个非头记录)的时间戳与alreadyinarchive.csvParentTrainingLesson...(第3个非头记录)匹配,但由于文件名不完全匹配,因此不应将其视为重复。
在大约2,000条记录中,只有大约300条不是重复的。
如果需要,我很乐意将copytoarchive.csvalreadyinarchive.csv操作到一个文件中。
起初,我试图通过嵌套的for /f循环来实现这一点,其中第一个for /f将一次读取copytoarchive.csv的一行,并通过第二个嵌套的for /f循环将相关标记(tokens=3)与alreadyinarchive.csv的每一行的相关标记进行比较。
根据要求,下面是我尝试的for /f循环:

setlocal enabledelayedexpansion

rem This code block takes the info from copytoarchive.csv and alreadyinarchive.csv, deletes any matching lines (e.g., files already in the archive), and generates filestocopy.csv which contains the old and new parent IDs for only those files needing to be copied to the archive.

set /a filenum=0
set /a totalfiles=0

for /f "delims=, tokens=2-4" %%k in (C:\path\copytoarchive.csv) do (
    set /a filenum+=1
    set /a totalfiles+=1
    call set fileID[!filenum!]=%%k
    call set filename[!filenum!]=%%l
    call :checkifexists
)

set oldfileID[1]=OldParent
set newparentID[1]=NewParent
if exist c:\path\filestocopy.csv del c:\path\filestocopy.csv
for /l %%q in (1,1,%totalfiles%) do (
    echo !newowner[%%q]!,!newparentID[%%q]!,!oldfileID[%%q]!,!newparentname[%%q]! >> c:\path\filestocopy.csv
)

exit /b

:checkifexists
    for /f "delims=, tokens=3" %%n in (C:\path\alreadyinarchive.csv) do (
        if not !filename[%filenum%]!==%%n (
            set fileparentID[%filenum%]=%%m
        )
    )
    goto :eof

虽然这在技术上是可行的,因为每个列表几乎有2,000行长,这会产生大约400万次迭代,这需要太长的时间(在我的i9-12900 PC上超过10分钟)才能完成。请注意,这只是一个更大的批处理文件的一部分。
我读了findstr,但我找不到一种方法来使用它只搜索一个字段。
我还安装了GNU CoreUtils,包括gawk。阅读gawk的PDF手册,似乎这可能是最好的路径,但我仍然在努力找到正确的参数传递给gawk,让它只搜索“名称”字段。
我找到了@perl的答案here,它看起来非常接近一个解决方案,但我不知道如何将其转换为我的用例。
任何帮助都很感激。

fnx2tebb

fnx2tebb1#

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION 
rem The following settings for the source directory and filenames are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.

SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
:: The first file is copytoarchive.csv
SET "filename1=%sourcedir%\q76378302.txt"
:: The second file is alreadyinarchive.csv
SET "filename2=%sourcedir%\q76378302_2.txt"
SET "outfile=%destdir%\outfile.txt"

(
FOR /f "usebackqskip=1delims=" %%e IN ("%filename1%") DO (
 rem %%e has each line in turn
 FOR /f "tokens=2*delims= " %%b IN ("%%e") DO (
  rem %%c has column 3 to eol
  SET "line=%%c"
  FOR /f "delims=?" %%o IN ("!line:.mp4=?!") DO FIND "%%o.mp4" "%filename2%">nul&IF ERRORLEVEL 1 ECHO %%e?"%%o.mp4"
 )
)
)>"%outfile%"

TYPE "%outfile%"

GOTO :EOF

rem在应用于真实的数据之前,请始终根据测试目录进行验证。
代码中的注解解释了大部分内容。
神奇的是!line:.mp4=?!子句。

  • 将当前值line中的.mp4替换为?

Batch无法子串metavariables%%e,因此必须将%%c传输到用户变量(line)以执行子串。需要line的 * 当前 * 值,因此替换在delayedexpansion模式下执行,因此格式为!var!Stephan's DELAYEDEXPANSION link
我使用?,因为它不能出现在文件名中。
不清楚您是想要实际的输出行还是只想要文件名,所以我提供了两个行,它们之间用?分隔

bq9c1y66

bq9c1y662#

嗯……首先,关于你的请求有几点意见:

  • 从你的问题来看,似乎UID字段也是不相关的,重复的字段是基于文件名列的,所以你对UID的描述让人困惑。
  • 在您的for /f "delims=, tokens=2-4" %%k in ( ...命令中包含逗号作为分隔符,但在您的文件中没有一个逗号!此外:
  • 文件名中包含空格!然后呢
  • 代码中的这一行:echo !newowner[%%q]!,!newparentID[%%q]!,!oldfileID[%%q]!,!newparentname[%%q]!表示输出字段由逗号分隔,没有空格...

你 * 没有 * 描述也没有发布你的文件的 * 真实的 * 格式,尽管这在评论中被要求了几次...
由于所有这些原因,我假设你发布的文件格式不正确,正确的文件应该是这些文件:

copytoarchive.csv

Owner,id,name,Parent
user@domain.com,1gyKqu_P0h3j1Vn-6EwUv_99q,PreschoolExampleLessonName-20230504_050216-Meeting Recording.mp4,1b-U8XU0jYVFCggoEH9E9wqUm
user@domain.com,14-sg-qSnn5GDAuftANdLxDXp,OneonOneExampleLessonName-20230510_043228-Meeting Recording.mp4,1TtaABRvoki4gNuyqRrlyTfzj
user@domain.com,1L9mQBJ6d3DIPbiIEyV7akArV,OtherYearLevelExampleLessonName-20230510_033024-Meeting Recording.mp4,1CdiBgePlVqPvtcEp83DmcUrotr
user@domain.com,1oHaFzLF_KcgVX-hZn5etBka9,TeacherTrainingLesson-20230510_000950-Meeting Recording.mp4,1QusVD-a9U16I-0GTP1t-Vd9Ez
user@domain.com,1_ewCEh37sZYpqZlr3TC8u2Yl,ExampleStaffMeeting-20230509_045403-Meeting Recording.mp4,1tOb7xV5OCMMebn2ab2KdXGvc
user@domain.com,1SyXjINXttrb3VKvpbjpm1y-V,ExampleLessonName-20230503_052304-Meeting Recording.mp4,13g_fYh9HYtnDtd4psHEZi

alreadyinarchive.csv

Owner,id,name,Parent
user@domain.com,1Zlnhqf6fSxTRT2JEmQS91cCX,PreschoolExampleLessonName-20230504_050216-Meeting Recording.mp4,1CdiBgePlVqPvtcEp83DmcUro
user@domain.com,1Lg2W0w8YGJytSgJl2JblBly3,OtherYearLevelExampleLessonName-20230510_033024-Meeting Recording.mp4,1TtaABRvoki4gNuyqRrlyTfzj
user@domain.com,1Q_K0D1RgZlz-LMlDUVrV0gGi,ParentTrainingLesson-20230510_000950-Meeting Recording.mp4,1b-U8XU0jYVFCggoEH9E9wq
user@domain.com,1LIrRoTGtADjQRg9IRmIlJ3oV,ExampleStaffMeeting-20230509_045403-Meeting Recording.mp4,1xVuHbE3pcWN1l7X109qTsIYZK
user@domain.com,1OHkH9Cg7i2-O-ZHXBr4wIYGZ,OneonOneExampleLessonName-20230510_043228-Meeting Recording.mp4,1U7Y2Xh4Qi3atCcVL262
user@domain.com,1jZsXB5TT0H0TRrvvZu5A3N1S,DifferentLessonName-20230503_052614-Meeting Recording.mp4,1eVS3QF_Sk_6fQkwF8PvTKQf

这样的进程应该避免使用任何外部(.exe)命令(如findstrfind),以便运行得更快。环境变量足以解决这个问题:

@echo off
setlocal EnableDelayedExpansion

rem Load alreadyinarchive's name field in "already" array putting the value *in the subscript*
rem in order to quickly check for it via IF DEFINED command
rem changing spaces in the name for underscores
for /F "tokens=3 delims=," %%a in (AlreadyInArchive.csv) do (
   set "name=%%a"
   set "name=!name: =_!"
   set "already[!name!]=1"
)

rem Process copytoarchive file and output lines with no duplicates
(for /F "tokens=1-4 delims=," %%a in (CopyToArchive.csv) do (
   set "name=%%c"
   set "name=!name: =_!"
   if not defined already[!name!] echo %%a,%%b,%%c,%%d
)) > filestocopy.csv

filestocopy.csv

user@domain.com,1oHaFzLF_KcgVX-hZn5etBka9,TeacherTrainingLesson-20230510_000950-Meeting Recording.mp4,1QusVD-a9U16I-0GTP1t-Vd9Ez
user@domain.com,1SyXjINXttrb3VKvpbjpm1y-V,ExampleLessonName-20230503_052304-Meeting Recording.mp4,13g_fYh9HYtnDtd4psHEZi

PS -你详细描述了不相关的数据,并没有描述足够的重要点...:(

相关问题