在目录中的 dat 文件中找到匹配的 file_id,并将其复制到其他目录

在目录中的 dat 文件中找到匹配的 file_id,并将其复制到其他目录

我有一个file_id = 840920,我必须只选择属于的子文件file_id = 840920。dat 文件的名称不同,但在所有 dat 文件中,父文件 id 可用。记录示例显示如下:

445973129|2602325065|840920|1|RUPATXEM14|LVP|||20180924 18:25:10
445973130|2602325066|840920|2|RP_STG_TEST_WED|LVP|||20180924 18:23

所以我只想将我的搜索映射到第三列并提取那些 dat 文件并将它们复制到不同的文件夹。

下面是我在 unix 中执行相同操作的代码。需要一些帮助来获得更多建议或更好的处理方法。我的问题是,matched_file_id当我单独运行 while 循环时,我能够打印值,但当我将它们作为代码的一部分包含时,代码不会打印显示matched_file_id值:有什么建议吗?

cat $TMP/TempBatchData.txt | while read FILE_ID #FILE_ID = 840920
do
for file in *CDI*.dat; do
echo $file >> all_CDI_LIST.txt
done
while IFS= read -r line; do
matched_file_id=`cat $line | cut -f3 -d"|" | sort -u` # echo all the third 
column values
done < "all_CDI_LIST.txt" 

if [[ $matched_file_id == $FILE_ID ]]; then 
echo $line >> final_cdi_list.txt
fi
done
done

答案1

问题、可疑片段:

  • $matched_file_id包含零个或多个值,$FILE_ID只有当有一个值时比较才会成功;
  • $matched_file_id每 设置一次,每 执行一次与 的line比较;$FILE_IDFILE_ID
  • done最后有一个额外的内容(?);
  • column values应该属于一条评论;
  • 变量没有被引用;
  • TMP应该设置。

这是一个重写的过程。它并不完全相同,但方法似乎更好:

TMP="/the/right/path"
find . -type f -name '*CDI*.dat' \
       -exec sh -c '
          <"$1" cut -f3 -d"|" | grep -qFx -f "$TMP/TempBatchData.txt"
       ' sh {} \; -print > final_cdi_list.txt

解释:

  1. find查找与该模式匹配的所有文件*CDI*.dat
  2. 对于每个这样的文件,都会运行一个 shell 来处理管道。
  3. cut提取第三列。
  4. grepquietly ( -q) 检查-F给定文件 ( ) 中的任何文字字符串 ( )是否存在于整行 ( )-f的输出中。cut-x
  5. 如果是,find将打印该文件的路径。

注意事项、差异、怪癖:

  • find以递归方式运行。要仅处理当前目录而不处理子目录,您需要-maxdepth 1(POSIX 不要求)或来自的 POSIX 解决方案这个问题或者让壳膨胀*CDI*.datfind *CDI*.dat -type f -exec …),但这也有其缺点。
  • find将打印以 为前导的路径./。要获取基本名称,您需要-printf '%f\n'(非 POSIX) 而不是-print或例如-exec basename {} \;(POSIX 兼容) 而不是-print
  • grep -F匹配文字字符串。在您的代码中,每一行都会$TMP/TempBatchData.txt经过两次隐式处理:

    1. read FILE_ID(相对于read -r FILE_ID
    2. 在里面[[ $matched_file_id == $FILE_ID ]](比较使用[[对右侧未加引号的字符串执行模式匹配,而不仅仅是普通的字符串比较)。


    我不确定您是否依赖这个。您可能需要调整我的代码。

  • 标题提到将文件复制到另一个目录。使用我的方法,您无需处理即可final_cdi_list.txt执行此操作。只需使用-exec cp {} "/another/directory" \;而不是 即可-print

查找匹配文件的全部工作都可以用 sole 来完成grep,不过你需要调整模式。例如:

grep -l '^[0-9]*|[0-9]*|840920|' *CDI*.dat

一个文件中可以包含许多模式(-f "$TMP/TempBatchData.txt"),但它们必须像上面那样。如果匹配的文件太多,*CDI*.dat您将得到“参数列表太长”的结果(for file in *CDI*.dat;您最初使用的方法不受此影响)。

也许可以调整目录结构(例如,仅*CDI*.dat当前目录和子目录中的文件、允许递归搜索或根本不允许子目录)和模式文件格式。这个想法是使用

grep -lr -f "$TMP/TempBatchData.txt"

或类似的东西。注意-rPOSIX 不要求这样做,在这个例子中,它的含义来自 GNU grep:递归读取当前工作目录下的所有文件。

单个grep过程应该比任何使用find -execread(并以任何方式匹配字符串)的解决方案更快。

相关内容