简体   繁体   English

查找,替换或插入-命令行

[英]Find, Replace or Insert - command Line

I have a list similar to : 我有类似的清单:

What do you want to do?
Import a text file by opening it in Excel
Import a text file by connecting to it
Export data to a text file by saving it
Change the delimiter that is used in a text file
Change the separator in all .csv text files

using SED I can find a match on 'connecting' and replace the line: 使用SED,我可以在“ connecting”上找到匹配项并替换行:

 sed 's^.*connecting.*^Import a text file by opening it^g' crontab

This should change the above list to : 这应该将上面的列表更改为:

What do you want to do?
Import a text file by opening it in Excel
Import a text file by opening it
Export data to a text file by saving it
Change the delimiter that is used in a text file
Change the separator in all .csv text files

However what I need to be able to do is: 但是,我需要做的是:

if a line exists containing the word connecting , then replace that line, if the line doesn't exist add it to the end of the list as a new line. 如果存在包含单词connecting ,则替换该行;如果该行不存在,则将其作为新行添加到列表的末尾。

I know I can do echo "Import a text file by opening it" >> list which would add the line to the end of the list, but is there anyway I can do this within one command ? 我知道我可以执行echo "Import a text file by opening it" >> list ,这会将行添加到列表的末尾,但是无论如何,我可以在一个命令中执行此操作吗? or commands that can be run in one instance ? 还是可以在一个实例中运行的命令?

Thanks 谢谢

An easy way is to use awk : 一种简单的方法是使用awk

awk 'BEGIN { s = "Import a text file by opening it" } /connecting/ { $0 = s; n = 1 } 1; END { if(!n) print s }' filename

That works as follows: 如下所示:

BEGIN {                                    # Before anything else:
  s = "Import a text file by opening it"   # Remember the string by a shorter
                                           # name so we don't have to repeat it
}
/connecting/ {                             # If a line contains "connecting",
  $0 = s                                   # replace the line with that string
  n = 1                                    # and raise a flag that we've done so.
}
1                                          # print
END {                                      # in the end:
  if(!n) {                                 # If the string wasn't yet printed,
    print s                                # do it now.
  }
}

Alternatively, you can use sed 's hold buffer. 另外,您可以使用sed的保持缓冲区。 For example: 例如:

sed '1 { x; s/.*/Import a text file by opening it/; x; }; /connecting/ { s/.*//; x; }; $ { G; s/\n$//; }' filename

This works as follows: 其工作原理如下:

1 {                                        # while processing the first line
  x                                        # swap hold buffer, pattern space
  s/.*/Import a text file by opening it/   # write text to pattern space
  x                                        # swap back.
}                                          # Now the hold buffer contains the
                                           # line we want to insert, and the
                                           # pattern space the first line.

/connecting/ {                             # For all lines: If a line contains
                                           # "connecting"
  s/.*//                                   # empty the pattern space
  x                                        # swap in hold buffer.
                                           # If this happened, the hold buffer
                                           # will be empty and the pattern space
                                           # will contain "Import a ..."
}
$ {                                        # Last line:
  G                                        # Append hold buffer to pattern space.
                                           # If the hold buffer is empty (i.e.,
                                           # was used somewhere else), this
                                           # appends a newline, so
  s/\n$//                                  # remove it if that happened.
}

Note that the sed code depends on the fact that there's only one line that contains "connecting." 请注意, sed代码取决于以下事实:只有一行包含“ connecting”。 If there were more such lines, they would be replaced with empty lines because the hold buffer is empty when the second line comes around. 如果有更多这样的行,则将它们替换为空行,因为当第二行出现时,保持缓冲区为空。 It is possible to handle that case, but you'd have to decide what should happen in it. 可以处理这种情况,但是您必须决定在其中应该发生什么。 Since you replied in the comments that there's only one such line, I didn't feel the need to guess. 既然您在评论中回答说只有这样一行,所以我不需要猜测。

You can try , with similar regex syntax than but far more powerful for theses issues. 您可以使用与类似的正则表达式语法尝试 ,但对这些问题的功能要强大得多。 It simply set a flag when at least one substitution has been done. 只要完成至少一个替换,它就简单地设置一个标志。 After parsing the whole file, in the END {} block, add the comment if the $flag variable has not been set: 解析完整个文件后,如果未设置$flag变量,请在END {}块中添加注释:

perl -pe '
    s/^.*connecting.*$/Import a text file by opening it/ and $done = 1;
    END { printf qq|%s\n|, q|Import a text file by opening it| unless $done }
' infile

When the line is found, it yields: 找到该行后,将产生:

What do you want to do?
Import a text file by opening it in Excel
Import a text file by opening it
Export data to a text file by saving it
Change the delimiter that is used in a text file
Change the separator in all .csv text files

When it's not found, it yields: 当找不到它时,将产生:

What do you want to do?
Import a text file by opening it in Excel
Export data to a text file by saving it
Change the delimiter that is used in a text file
Change the separator in all .csv text files
Import a text file by opening it

If it appears more than once, change both but it doesn't append anything: 如果出现多次,请同时更改两者,但不添加任何内容:

What do you want to do?
Import a text file by opening it in Excel
Import a text file by opening it
Export data to a text file by saving it
Change the delimiter that is used in a text file
Import a text file by opening it
Change the separator in all .csv text files

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM