查找、替换或插入 - 命令行
Find, Replace or Insert - command Line
我有一个类似的列表:
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 我可以在 'connecting' 上找到匹配项并替换行:
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
将行添加到列表的末尾,但是无论如何我可以在一个命令中完成吗?或者在一个实例中可以是 运行 的命令?
谢谢
您可以尝试 perl, with similar regex syntax than 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
一个简单的方法是使用 awk
:
awk 'BEGIN { s = "Import a text file by opening it" } /connecting/ { [=10=] = 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",
[=11=] = 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
代码取决于只有一行包含 "connecting." 如果有更多这样的行,它们将被替换为空行,因为保持缓冲区是空的当第二行出现时。可以处理这种情况,但您必须决定其中应该发生什么。既然你在评论里回复说只有这样一行,我觉得没必要去猜。
我有一个类似的列表:
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 我可以在 'connecting' 上找到匹配项并替换行:
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
将行添加到列表的末尾,但是无论如何我可以在一个命令中完成吗?或者在一个实例中可以是 运行 的命令?
谢谢
您可以尝试 perl, with similar regex syntax than 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
一个简单的方法是使用 awk
:
awk 'BEGIN { s = "Import a text file by opening it" } /connecting/ { [=10=] = 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",
[=11=] = 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
代码取决于只有一行包含 "connecting." 如果有更多这样的行,它们将被替换为空行,因为保持缓冲区是空的当第二行出现时。可以处理这种情况,但您必须决定其中应该发生什么。既然你在评论里回复说只有这样一行,我觉得没必要去猜。