第一个文件包含:
#. This is the file name to process: waveheight.txt
#. This is the latest data to process if exists: waveheightNew.txt
FilNam=Project2128/Input/waveheightNew.txt
if [[ ! -f ${FilNam} ]]; then FilNam=Project2128/Input/waveheight.txt; fi
第二个文件包含:
#. This is the file name to process: waveheightBin.txt
#. This is the latest data to process if exists: waveheightNewBin.txt
FilNam=Project2128/Input/waveheightNewBin.txt
if [[ ! -f ${FilNam} ]]; then FilNam=Project2128/Input/waveheightBin.txt; fi
.txt
现在我需要通过更改为Bin.txt
?来处理文件。使用sed "s/.txt/Bin.txt/"
将导致BinBin.txt
第二个文件。到sed "s/Bin.txt/.txt/"
那时就sed "s/.txt/Bin.txt/"
显得尴尬了。
跳过不需要的匹配会更明智吗?
答案1
您可以Bin
在文本中包含要替换的内容(如果存在),这会导致它被自身替换:
sed 's/\(Bin\)\{0,1\}\.txt/Bin.txt/g'
或者如果您sed
支持 ERE -E
(或者-r
对于某些旧版本的 GNU 或 busybox sed
):
sed -E 's/(Bin)?\.txt/Bin.txt/g'
当心.
是一个匹配任何单个字符的正则表达式运算符。您需要\.
匹配文字点。
答案2
您可以使用 perl 负向后查找来匹配.txt
,但只有它不是Bin.txt
。
perl -pe 's/(?<!Bin)\.txt/Bin.txt/g'
因此,要测试:
$ echo 'Bin.txt foo.txt' | perl -pe 's/(?<!Bin)\.txt/Bin.txt/g'
Bin.txt fooBin.txt
不幸的是,sed
不提供这种构造。
答案3
您可以使用 进行条件替换sed
,例如,您可以测试该行是否已包含Bin.txt
,如果不包含则仅执行替换。
sed '/Bin\.txt/!s/\.txt/Bin.txt/'
这假设每行只需要一次替换。
您也可以无条件地进行替换,然后在出现错误时进行更正,正如您在问题中暗示的那样,但在同一调用中sed
:
sed -e 's/\.txt/Bin.txt/' -e 's/BinBin/Bin/'
答案4
您可以按GNU-sed
如下所示执行此操作:
echo "$Filnam" |\
sed -e '
s/\.txt/\n&/;T # try to place a newline marker to the left of .txt, quit if unsuccessful
s/Bin\n/Bin/;t # If the marker turned out to be just to the right of Bin => Bin.txt already
# existed in the name, so we needn"t do anything n take away the marker n quit
s/\n/Bin/ # Bin could not be found adjacent to .txt so put it n take away the marker as well
'
### Below is the POSIX sed code for accomplishing the same:
sed -e '
s/\.txt/\
&/;/\n/!b
s/Bin\n/Bin/;/\n/!b
s/\n/Bin/
'