将新行附加到多个文件

将新行附加到多个文件

我正在尝试使用以下命令将新行附加到多个文件:

find -name *.ovpn -exec sh echo "line to append" >> {} \;

在执行此操作之前,我运行了不同的命令以确保它能按我预期的方式工作:

find -name *.ovpn -exec sh echo "hello" \;

但这一切只是为找到的每个文件打印出“sh:0:无法打开回显”。

答案1

问题很少。

>>在您的第一个命令中,将被您当前的shell解释为重定向到字面上名为的文件{},除非它被引用。

*.ovpn可能会在运行之前通过 shell 通配符进行扩展find。如果当前目录中至少有一个对象与模式匹配,就会发生这种情况。您确实想引用它。比较这个问题

你得到答案是Can't open echo因为你确实sh要打开echo。要执行命令你需要sh -c

find不指定路径是不可移植的(比较这个问题)。虽然您可能不会遇到这种情况,但我提到这个问题是为了让答案对其他用户更有用。

这是第一个命令的改进版本有点工作(不要运行,继续阅读):

find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "{}"' \;

请注意,我必须{}在单引号内加双引号。这些双引号被“看到”,并使sh带空格等的文件名作为重定向目标。如果没有引号,您最终可能会得到echo "line to append" >> foo bar.ovpn类似于 的结果,这相当于echo "line to append" bar.ovpn >> foo。引用可以使它变成这样echo "line to append" >> "foo bar.ovpn"

不幸的是包含的文件名"会破坏这种语法。

{}传递的正确方法sh不是将其包含在命令字符串中,而是将其内容作为单独的参数传递:

find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$0"' {} \;

$0命令字符串内部扩展为我们sh获取的第一个参数-c '…'。现在即使"在文件名中也不会破坏语法。

通常(比如在脚本中)指的是您使用的第一个参数$1。这就是一些用户宁愿使用虚拟参数的原因$0,如下所示:

find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$1"' dummy {} \;

如果它是一个脚本,$0将扩展为它的名称。这就是为什么看到它dummy实际上是sh(或bash,如果有人调用bash -c …等;检查此链接)。 像这样:

find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$1"' sh {} \;

但是等等!为每个文件find调用一个单独的进程sh。我不希望您有数千个.ovpn文件,但一般来说,您可能希望处理许多文件而不产生不必要的进程。我们可以优化方法,以便tee -a可以作为单个进程写入多个文件:

find . -name '*.ovpn' -exec sh -c 'echo "line to append" | tee -a "$@" >/dev/null' sh {} +

注意{} +,这会一次传递多个路径。在执行的命令中,sh -c我们使用 检索它们"$@",这会扩展为。在这种情况下,必须有"$1" "$2" "$3" …一个填充 (未使用) 的伪参数。$0

一般来说还存在这个问题:为什么printf比 更好echo但是在这种情况下,您使用的echo没有选项,并且它获取的字符串是静态的,所以应该没问题。

答案2

我的脚本将多行保存到.csv文件中:

#! /bin/bash
while [ 1 ]
do
    sleep 1s
    str="\""$(date)"\""
    echo   ${str} >>333.csv
    
    # begin add next row
    echo ",\"" >>333.csv
    # append multiline result
    ps >>333.csv
    # end add next row
    echo "\"" >>333.csv
    
    # begin add next row
    echo ",\"" >>333.csv
    # append multiline result
    df -h >>333.csv
    # end add next row
    echo "\"" >>333.csv
    
    sed -i ":a;N;s/\"\n\,/\"\,/g;ta" ./333.csv
done

相关内容