将 awk 与 find -exec 一起使用

con*_*ipo 5 unix awk find

我有一个包含 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 命令,但是我在将文件输出到正确的位置时遇到了问题。

当在数据/全部/

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

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

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

pab*_*ouk 6

我究竟做错了什么?

您正在使用重定向> ../pos/'{}',就好像它是由find或处理的一样,awk但重定向是由外壳处理的。在您的情况下,这意味着您只能重定向整个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
Run Code Online (Sandbox Code Playgroud)

原来的方式-exec效率较低,因为对于每个文件,除了启动一个 shell 之外,awk多级转义在这里非常复杂:

find . -type f -exec sh -c 'awk "{print \$2}" "{}" > "../pos/{}"' \;
Run Code Online (Sandbox Code Playgroud)

也可能有一个替代解决方案在内部进行重定向awk


Jac*_*era 3

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

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

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

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