如何在 bash 中循环一个文件,但基于另一个文件的顺序?

如何在 bash 中循环一个文件,但基于另一个文件的顺序?

假设我有这个文件,名为Dependencies

Accounts
Blog
Configuration
Contacts
Entities
Faqs
Forms
Galleries
Geo
Globalization
Logs
Media
Navigation
Notifications
Orders
Payment
Places
Pricing
Products
Sales
Seo
Services
Shipment
Social
Subscriptions
Taxonomy
Ticketing

我可以使用多种方法循环它,并将每一行作为变量来对其执行某些操作。

然而,我还有另一个名为 的文件Order,如下所示:

Entities
Globalization
Configuration
Accounts
Contacts
Taxonomy
Geo
Media
Places
Products
Services
Orders
Shipment
Payment
Sales
Social

这意味着我需要Dependencies根据Order文件中指定的顺序加载行。如果文件中不存在某行Order,它将转到列表的末尾,并且那里的顺序并不重要。

dependencies.OrderBy(i => orders.IndexOf(i))在 C# 中,我可以根据指定的顺序轻松列出我的依赖项。

但我不知道如何在 bash 中做到这一点。

答案1

我假设每一行Dependencies都是唯一的。对于 也一样Order。对于您的用例来说,这种假设似乎是合理的。

调用这个:

grep -xFf Dependencies Order; grep -vxFf Order Dependencies

第一个grep给出了 inDependencies和 in的行Order,按照从 的顺序Order

第二个grep给出了在 中Dependencies但不在 中的行Order。这些是Dependencies第一个 未打印的行grep

总共Dependencies应该出现每一行。

唯一性的假设是相关的,因为在 中 重复的行Dependencies或 中 重复的行Order可能会在输出中出现多次,但可能不与 中 的计数完全相同Dependencies。它在输出中的计数将取决于grep打印它的位置。

答案2

使用awk

awk '
    FNR == NR {
        words[$0]
        next
    }
    ($0 in words) {
        print
        delete words[$0]
    }
    END {
        for (word in words)
            print word
    }' Dependencies Order

首先将行作为键读取Dependencies到关联数组中。words然后它读取 中的行Order,如果字符串是words数组中的键,它会打印它并从数组中删除该键。最后,所有剩余的密钥words都会被打印出来。

请注意,打印最终行列表的顺序可能不固定,因为它取决于数组中键的检索顺序words

测试:

$ awk 'FNR == NR { words[$0]; next } ($0 in words) { print; delete words[$0] } END { for (word in words) print word }' Dependencies Order
Entities
Globalization
Configuration
Accounts
Contacts
Taxonomy
Geo
Media
Places
Products
Services
Orders
Shipment
Payment
Sales
Social
Galleries
Subscriptions
Seo
Faqs
Notifications
Ticketing
Forms
Navigation
Blog
Pricing
Logs

上面的代码将删除重复项。如果您想保留 中的任何重复项Dependencies,请跟踪该文件中每一行被查看的次数,然后输出该行的次数。

awk '
    FNR == NR {
        words[$0]++
        next
    }
    ($0 in words) {
        while (words[$0]-- > 0) print
        delete words[$0]
    }
    END {
        for (word in words)
            while (words[word]-- > 0) print word
    }' Dependencies Order

答案3

如果使用zsh而不是bash,您可以通过执行以下操作来采用相同的 indexof() 方法:

order=( ${(f)"$(<Order)"} )
dependencies=(
  /(Ne['
        reply=( ${(f)"$(<Dependencies)"} )
     ']noe['
        REPLY=$order[(ie)$REPLY]
     '])
)

进而:

for dep in $dependencies; do
  ...
done

循环它们。

我们使用noe[code]glob 限定符根据修改的值以数字方式对 glob 扩展进行n排序。 glob 扩展(此处应用于)是通过使用限定符填充文件行(就像我们之前用文件行填充数组一样)来播种的。o$REPLYcode/$replyDependencies$orderOrdere

$order[(ie)$REPLY]扩展为与 匹配i的第一个元素的索引,xact 与 匹配。如果不匹配,则 1 + 最后一个索引。$order$REPLYee

另一种方法是使用数组交集${a:*b}和减法 ( ${a:|b}) 运算符:

order=( ${(f)"$(<Order)"} )
dependencies=( ${(f)"$(<Dependencies)"} )

dependencies=(
  ${order:*dependencies} # elements or $order that are also in $dependencies
  # followed by:
  ${dependencies:|order} # elements of $dependencies that are not in $order
)

相关内容