Вы можете включить Bin
в текст для замены, если это приведет к замене самого себя:
sed 's/\(Bin\)\{0,1\}\.txt/Bin.txt/g'
Или если ваш sed
поддерживает ERE с-E
(или -r
для некоторых более старых версий GNU или busyboxsed
):
sed -E 's/(Bin)?\.txt/Bin.txt/g'
Осторожно .
— это оператор регулярного выражения, который соответствует любому одиночному символу. Вам нужно, чтобы \.
соответствовало буквальной точке .
Вы можете выполнить условную замену с sed
, например, вы можете проверить, содержит ли строка уже Bin.txt
и выполнить замену, только если это не так.
sed '/Bin\.txt/!s/\.txt/Bin.txt/'
Это предполагает, что потребуется только одна замена на строку.
Вы также можете сделать замену безоговорочно, а затем исправить ее, если она пошла не так, как вы намекнули в вопросе, но в том же вызовеsed
:
sed -e 's/\.txt/Bin.txt/' -e 's/BinBin/Bin/'
Вы можете использовать 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
не предлагает такой конструкции.
Вы можете сделать это с помощью 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/
'