【问题标题】:Search within a directory structure using find, sed and awk使用 find、sed 和 awk 在目录结构中搜索
【发布时间】:2018-10-16 17:11:53
【问题描述】:

这一系列命令编辑idea.js并导出为idea.csv

sed -n '/^get\.idea/s/^.*(\(.*\)).*/\1/ p' idea.js | 
awk -F, 'BEGIN {print "idea, description";OFS=","} (NR % 2 ) == 1
         {save=$2} (NR % 2) == 0 {print save, $2}' > idea.csv

我需要做的是运行完全相同的命令,但使用 find 在多个目录中搜索具有相同 idea.js 名称的多个文件,导出每个文件在找到 idea.js 的同一目录中。

我尝试了很多方法,但我得到了不同的错误。

这里的结果不是预期的:

find . -type f -name "idea.js" \( \ 
    -exec sed -n '/^get\.idea/s/^.*(\(.*\)).*/\1/ p' idea.js  {} \; -o \
    -exec true \; \) \
    -exec awk -F, 'BEGIN {print "idea, description";OFS=","} (NR % 2 ) == 1 
                   {save=$2} (NR % 2) == 0 {print save, $2}' > idea.csv {} \;

这里:

find . -type f -name "idea.js" \( 
    -exec sed -n '/^get\.idea/s/^.*(\(.*\)).*/\1/ p' idea.js | 
    awk -F, 'BEGIN {print "idea, description";OFS=","} (NR % 2 ) == 1
            {save=$2} (NR % 2) ==0 {print save, $2}' > idea.csv {} \) 

我收到此错误:

    idea, description
awk: cannot open {} (No such file or directory)
find: missing argument to `-exec'
Try 'find --help' for more information.

我想学习如何直接从命令行执行此操作,并作为脚本以这种方式执行:

$ sh script.sh

感谢您的帮助。

【问题讨论】:

  • {} 被替换为匹配项。为什么将它们放在输出重定向 (>) 之后?它们应该在sed命令中(而不是idea.js,它不包含路径。另外,'('代表什么?见这里stackoverflow.com/questions/307015/…如何在-exec中使用管道
  • 我真的没有足够的知识,我只是在试验命令,你能告诉我怎样才能做好吗?
  • find . -type f -name "idea.js" -exec sh -c "sed -n '/^get\.idea/s/^.*(\(.*\)).*/\1/ p' {} | awk -F, 'BEGIN {print \"idea, description\";OFS=\",\"} (NR % 2 ) == 1 {save=\$2} (NR % 2) ==0 {print save, \$2}'" \; ?
  • 您现在正在做的事情,虽然您可能能够从中获得预期的输出,但这只是一个 hack。到目前为止,您已经获得了为命令编写有效语法的帮助,但无论您尝试做什么,它都是错误的命令。请参阅How to Ask,尤其是有关提供minimal reproducible example 的部分。一旦你这样做了,我们就能帮助你得到正确的答案。
  • @Nico202,您提供的建议存在严重的安全问题。 {} 应该 永远 成为传递给 sh -c 以在调用 shell 之前进行替换的字符串的一部分——如果是这样,嵌入在 find 标识的路径中的代码可以被解析和执行.如果有人运行d=$'tmp/$(rm -rf ~)\'$(rm -rf ~)\''; mkdir -p "$d" && touch "$d/idea.js,那么将来调用 OP 的代码(find 覆盖该目录树)将是一个定时炸弹。只有从脚本中替换文件名out-of-band 来执行是安全的。

标签: shell awk sed find


【解决方案1】:
find . -type f -name idea.js -exec sh -c '
    for idea do
        sed -n "/^get\.idea/s/^.*(\(.*\)).*/\1/ p" "$idea" | 
        awk -F, "BEGIN {print \"idea, description\";OFS=\",\"} (NR % 2 ) == 1
                 {save=\$2} (NR % 2) == 0 {print save, \$2}" >"${idea%.js}.csv"
    done' sh {} +

这会使你的 shell 代码 sn-p 或多或少保持不变(除了我已经安排代码中的单引号现在是双引号,并且输出文件名是通过替换扩展名从输入文件名计算出来的) , 并通过find 执行。 find 将为代码提供idea.js 文件的路径名列表,代码将遍历这些文件。

另一种方法是将您的代码放入 shell 脚本中:

#!/bin/sh

for idea do
    sed -n '/^get\.idea/s/^.*(\(.*\)).*/\1/ p' "$idea" | 
    awk -F, 'BEGIN {print "idea, description";OFS=","} (NR % 2 ) == 1
             {save=$2} (NR % 2) == 0 {print save, $2}' > "${idea%.js}.cvs"
done

然后为所有找到的路径名调用此脚本:

find . -type f -name idea.js -exec ./script.sh {} +

【讨论】:

  • 一般来说是好的方法,但是单引号字符串中的单引号(在第一个示例中)效果不佳。第二种方法当然是安全的。
  • @CharlesDuffy 错过了那个。现在修好了。谢谢。
猜你喜欢
  • 2013-09-11
  • 2016-11-27
  • 2017-11-12
  • 1970-01-01
  • 1970-01-01
  • 2022-01-02
  • 1970-01-01
  • 1970-01-01
  • 2011-05-12
相关资源
最近更新 更多