使用 awk 和 find -exec

使用 awk 和 find -exec

我有一个包含 14 个目录的目录结构,其中包含一堆包含三列格式(用制表符分隔)数据的文件。我打算使用 find 和 awk 从每个文件中提取第二列,并使用相同的文件名但在不同的根文件夹下输出它。这是我的目录的草图。

data/all -> AA、AB、AC、AD ...(A* 为包含以 3 列格式存储数据的文件的文件夹,例如 AA100.txt、AA101.txt...)

我想要拥有同名的修改过的(单列)文件,但都在新的根目录 data/pos 下(而不是 data/all/)->AA、AB、AC、AD......(同样,每个都包含 A*100.txt、A*101......)

我尝试使用 find -exec 并给它 awk 命令,但是在将文件输出到正确的位置时遇到了问题。

当处于 data/all/

查找 * -type f -exec awk'{print$2}''{}'> ../pos/'{}'\;

但是在输出文件时,{} 作为输入文件的通配符似乎不起作用?

我做错了什么?(顺便说一下,我在 ubuntu 服务器上)

答案1

如果您想要的是所有文件,可以尝试不使用 find。在 中data/all/,运行以下命令:

for file in ./*; do awk '{print$2}' "$file" > "../pos/$(basename $file)"; done

如果您想要覆盖下的整个层次结构中的文件/data/all,您可以globstar在使用 bash 时启用该选项(我相信这在 zsh 上“有效”),然后使用来**匹配所有文件:

shopt -s globstar
for file in ./**; do awk '{print$2}' "$file" > "../pos/$(basename $file)"; done

答案2

我究竟做错了什么?

您使用重定向的方式> ../pos/'{}'好像它是由find或处理的awk,但重定向是由 shell 处理的。 在您的例子中,这意味着您只能重定向整个的输出find(而不是 的输出awk)。

请注意,您通常不需要使用通配符作为*的起始路径。这是您想要的find常用方法吗?或者有什么理由吗?find .find *

解决方案

find与 Jacobo de Vera 的解决方案相比,我们将在这里保持灵活性。awk在 shell 循环中运行:

find . -type f -print0 |
  while read -r -d $'\0' x; do
    awk '{print $2}' "$x" > "../pos/$(basename "$x")"
  done

原始的方式-exec效率较低,因为除了 之外,还会为每个文件启动一个 shell,awk而且这里的多级转义相当复杂:

find . -type f -exec sh -c 'awk "{print \$2}" "{}" > "../pos/{}"' \;

也可能存在在内部进行重定向的替代解决方案awk

答案3

查找/路径 -exec ls -l {} \; | awk'{print$1}'

相关内容