我的列表类似于:
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
使用SED我可以在'连接'上找到匹配并替换该行:
sed 's^.*connecting.*^Import a text file by opening it^g' crontab
这应该将上面的列表更改为:
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
然而,我需要做的是:
如果存在包含单词connecting
的行,则替换该行,
如果该行不存在,请将其作为新行添加到列表的末尾。
我知道我可以echo "Import a text file by opening it" >> list
将行添加到列表末尾,但无论如何我可以在一个命令中执行此操作吗?或者可以在一个实例中运行的命令?
由于
答案 0 :(得分:2)
一种简单的方法是使用awk
:
awk 'BEGIN { s = "Import a text file by opening it" } /connecting/ { $0 = s; n = 1 } 1; END { if(!n) print s }' filename
其工作原理如下:
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.
}
}
或者,您可以使用sed
的保留缓冲区。例如:
sed '1 { x; s/.*/Import a text file by opening it/; x; }; /connecting/ { s/.*//; x; }; $ { G; s/\n$//; }' filename
其工作原理如下:
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.
}
请注意,sed
代码取决于只有一行包含"连接。"如果有更多这样的行,它们将被替换为空行,因为当第二行出现时,保持缓冲区为空。有可能处理这种情况,但你必须决定它应该发生什么。由于您在评论中回复说只有一条这样的行,我觉得不需要猜测。
答案 1 :(得分:0)
您可以尝试perl,使用与sed类似的正则语法,但对于这些问题要强大得多。它只是在至少完成一次替换时设置了一个标志。解析整个文件后,在END {}
块中,如果尚未设置$flag
变量,请添加注释:
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
找到该行后,它会产生:
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
如果找不到,则产生:
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
如果它出现不止一次,请更改两者,但它不会附加任何内容:
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