在find命令中获取当前目录并在sed中使用-单行

时间:2019-07-15 16:09:00

标签: sed find

我正在使用它在子目录中查找具有特定名称的文件,然后编辑一些内容:

find prod -type f -name "file.txt" -exec sed -i '' -e "s,^varname.*$, varname = \"$value\"," {} +

如何获取当前目录的名称(不是执行脚本的目录,而是找到文件的目录)并将其插入替换文本?像这样:

find prod -type f -name "file.txt" -exec sed -i '' -e "s,^ varname.*$, varname = \"$value/$dirname\"," {} +

我希望将其保持为单线。我最近的尝试是这样,但是替换没有用,我觉得必须有一个更简单的语法:

find prod -type f -name "file.txt" -exec sh -c '
  for file do
    dirname=${file%/*}
  done' sed -i '' -e "s,^varname.*$, varname = \"$value/$dirname\"," {} +

示例:

value=bar

file.txt输入:

varname = “foo”

file.txt输出:

varname = “bar/directory_name”

3 个答案:

答案 0 :(得分:1)

您可以使用GNU awk以相同的方式执行此操作:

您使用的sed命令可以替换为:

#include <iostream>

using namespace std;

int primes[10] = {0, 3, 5, 7, 11, 13, 17, 19, 23, 29};
int n;
int maxPow[10] = {0, 19, 13, 11, 8, 8, 7, 7, 6, 6};
int powNow[10];
int divisors = 1;
unsigned long long minOdd = 9223372036854775807;

unsigned long long power(int base, int exponent) {
    unsigned long long result = 1;
    while (exponent) {
        if (exponent & 1)
            result *= base;
        base *= base;
        exponent /= 2;
    }
    return result;
}

bool findMinOdd(int stage) {
a:
    int divisorsHere = 1;
    for (int i = 1; i <= 9; i++) divisorsHere *= (powNow[i] + 1);
    if (divisorsHere == divisors) {
        unsigned long long number = 1;
        for (int i = 1; i <= 9; i++) {
            if (number < 2147483648 && number < minOdd)
                number *= power(primes[i], powNow[i]);
            else {
                powNow[stage] = 0;
                return 1;
            }
        }
        minOdd = min(minOdd, number);
        return 0;
    }
    if (divisorsHere > divisors) {
        powNow[stage] = 0;
        return 1;
    }
    while (powNow[stage] < maxPow[stage]) {
        powNow[stage]++;
        if (stage == 9)
            goto a;
        if (findMinOdd(stage + 1)) {
            powNow[stage] = 0;
            return 0;
        }
    }
    powNow[stage] = 0;
    return 0;
}

int main() {
    cin >> n;
    int factor = 2;
    while (factor * factor <= n) {
        if (!(n % factor)) {
            int exponent = 0;
            do n /= factor, exponent++;
            while (!(n % factor));
            divisors *= (exponent + 1);
        }
        factor += (factor == 2 ? 1 : 2);
    }
    if (n > 1)
        divisors *= 2;
    findMinOdd(1);
    cout << minOdd;
}

所以您的Memory limit exceeded会读:

Time limit exceeded

答案 1 :(得分:0)

您需要使用-execdir并生成一个shell:

find ... -execdir \
  bash -c 'sed -i "" -e "s,^ varname.*$, varname = \"$value/${PWD}\"," "$1"' -- {} +

-execdir在文件的父文件夹中运行sed,而不是在运行find的文件夹中运行。这允许使用 $PWD


更多说明:我用两个参数调用bash:

-exec bash -c '... code ...' -- {}
                             ^^ ^^

我将--用作占位符。当用-c调用时,bash开始在$0而不是$1处索引参数。 ($0通常包含脚本的名称)。这样就可以将$1中的文件名使用{},这样更容易阅读和理解。

答案 2 :(得分:0)

这可能对您有用(GNU sed和并行):

find prod -type f -name "file.txt" | 
parallel -qa- --link sed -i 's#\(varname=\).*#\1"{2}{1//}"#' {1} ::: $value

我们为并行命令提供2个源。第一个来源是使用并行选项find的{​​{1}}命令中的文件列表。第二个源是变量-a -,它只是单个值,它使用并行选项$value链接到第一个源。使用并行选项--link引用sed命令,并应用常规的正则表达式规则,不同之处在于,首先并行解释值-q{2}来表示第二个源,而分别是第一个来源的目录。

要根据需要检查并行命令,请使用{1//}选项并在实际运行之前检查输出。