【问题标题】:Using sed to append to a line in a file使用 sed 追加到文件中的一行
【发布时间】:2020-12-21 19:49:15
【问题描述】:

我正在运行一个脚本,以使用我使用要更新的文件中的字符串运行的命令的输出。

for CLIENT in `cat /home/"$ID"/file.txt | awk '{print $3}'`
do
  sed "/$CLIENT/ s/$/ $(sudo bpgetconfig -g $CLIENT -L | grep -i "version name")/" /home/"$ID"/file.txt >> /home/"$ID"/updated_file.txt
done

输出为每一行打印一次整个文件,并更新相关匹配行。

如何对其进行排序,使其仅将匹配的行发送到新文件。

输入文件包含类似于以下的行:

"Host OS" "OS Version" "Hostname" 

我想运行一个脚本,该脚本将使用主机名来运行命令并获取主机上应用程序的详细信息,然后仅将应用程序版本打印到包含主机的行尾:

"Host OS" "OS Version" "Hostname" "Application Version

【问题讨论】:

  • 匹配是否会发生在文件中的任何位置,或者您是否打算简单地找到客户在第三个字段中所在的行?那么这又是另一种反模式,也是相当大规模逻辑改进的另一种途径。
  • 您是在附加相同的字符串,还是 command 某些命令会根据 CLIENT 而变化?几乎可以肯定,有一种简单的方法可以实现您想要的,如果您能描述它是什么,将会有所帮助。
  • 该文件包含类似于以下的行: ** "Host OS" "OS Version" "Hostname" ** 我想运行一个脚本,该脚本将使用主机名来运行命令并获取有关的详细信息主机上的应用程序,然后仅将应用程序版本打印到主机所在行的末尾:**“主机操作系统”“操作系统版本”“主机名”“应用程序版本”**
  • 文件中的字符串是否真的包含引号和引号内的空格?
  • 抱歉,如果问题的格式不正确,仍在学习中。文件中有空格,但没有引号。

标签: shell awk sed sh


【解决方案1】:

直接的答案是使用sed -n 默认不打印每一行,并在您想要打印的地方添加p 命令。但是在循环中运行sed 几乎总是错误的做法。

以下内容避免了useless catdon't read lines with for 反模式、obsolescent backticks 和循环;但在不知道您的文件是什么样子的情况下,这是相当投机的。特别是,command 是否需要为每场比赛单独运行?

file=/home/"$ID"/file.txt
pat=$(awk '{ printf "\\|$3"}' "$file")
sed -n "/${pat#\\|}/ s/$/ $(command)/p' "$file" >> /home/"$ID"/updated_file.txt

这里的主要问题是将我们想要匹配的所有模式收集到一个正则表达式中,然后只运行一次sed

如果command 需要为每一行单独运行,这将无法开箱即用。也许然后再转回一个循环。如果您的任务实际上只是为文件中的每一行运行一个命令,请尝试

while read -r line; do
    # set -- $line
    # client=$3
    printf "%s " "$line"
    command
done <file >>new_file

在您运行 command 之前,我包含但注释掉了将第三个字段提取到 $client 的命令。

(您的私有变量的名称不应全部大写;这些名称是为系统变量保留的。)

也许事实上这就是你所需要的:

while read -r os osver host; do
    printf "%s " "$os" "$osver" "$host"
    command "$host" something something
done </home/"$ID"/file.txt >/home/"$ID"/updated_file.txt

这假设command 的输出是格式良好的单行输出,最后有一个换行符。

【讨论】:

    【解决方案2】:

    您正在做的事情非常脆弱(例如,如果$CLIENT 表示的字符串出现在其他行上或在一行上多次出现或作为子字符串或包含正则表达式元字符或...,它将中断)并且效率低下(您在循环的每次迭代中读取一个 file.txt,而不是总共读取一次)并使用反模式(例如,使用 for 循环来读取输入行,加上 UUOC,加上不推荐使用的反引号等)

    相反,假设您要运行的commandprintf '%s' 'the_third_string' | wc -c,以用其字符数替换每个第三个字符串。然后你会这样做:

    while read -r a b c rest; do
        printf '%s %s %s %s\n' "$a" "$b" "$(printf '%s' "$c" | wc -c)" "$rest"
    done < file
    

    或者如果您有更多事情要做,那么值得使用 awk:

    awk '{
        cmd = "printf \047%s\047 \047" $3 "\047 | wc -c"
        if ( (cmd | getline line) > 0 ) {
            $3 = line
        }
        close(cmd)
        print
    }' file
    

    例如给定这个输入(Rabbie Burns 提供):

    When chapman billies leave the street,
    And drouthy neibors, neibors, meet;
    As market days are wearing late,
    And folk begin to tak the gate,
    While we sit bousing at the nappy,
    An' getting fou and unco happy,
    We think na on the lang Scots miles,
    The mosses, waters, slaps and stiles,
    That lie between us and our hame,
    Where sits our sulky, sullen dame,
    Gathering her brows like gathering storm,
    Nursing her wrath to keep it warm.
    

    我们得到:

    $ awk '{cmd="printf \047%s\047 \047"$3"\047 | wc -c"; if ( (cmd | getline line) > 0 ) $3=line; close(cmd)} 1' file
    When chapman 7 leave the street,
    And drouthy 8 neibors, meet;
    As market 4 are wearing late,
    And folk 5 to tak the gate,
    While we 3 bousing at the nappy,
    An' getting 3 and unco happy,
    We think 2 on the lang Scots miles,
    The mosses, 7 slaps and stiles,
    That lie 7 us and our hame,
    Where sits 3 sulky, sullen dame,
    Gathering her 5 like gathering storm,
    Nursing her 5 to keep it warm.
    

    【讨论】:

      【解决方案3】:

      这可能对你有用(GNU sed、bash/dash):

      echo "command () { expr length \"\$1\"; }" >> funlib
      sed -E 's/^((\S+\s){2})(\S+)(.*)/. .\/funlib; echo "\1$(command "\3")\4"/e' file
      

      作为命令示例,我创建了一个名为 command 的函数并将其附加到当前目录中的文件 funlib 中。

      sed 调用获取 funlib 并在字符串插值内的替换命令的 RHS 中运行 command 函数,由 echo 命令显示,评估标志 e 使之成为可能.

      注意评估使用dash shell 或/bin/sh 符号链接到的任何内容。

      【讨论】:

        猜你喜欢
        • 2012-04-02
        • 2017-08-11
        • 1970-01-01
        • 2012-10-02
        • 2013-12-05
        • 1970-01-01
        • 2013-02-16
        • 2015-06-29
        • 2019-01-20
        相关资源
        最近更新 更多