3

I have code in a script similar to this...

smbconffile="/etc/samba/smb.conf"
sed -i 's/.*[\[CMI\]]/\[CMI\$\]/' $smbconffile && echo "Success" || "Failed"
sed -i 's/.*[\[LOCAL\]]/\[LOCAL\$\]/' $smbconffile && echo "Success" || "Failed"
sed -i 's/.*[\[NATIONAL\]]/\[NATIONAL\$\]/' $smbconffile && echo "Success" || "Failed"

this changes the names of the shares in the samba conf (smb.conf) to the CMI$, LOCAL$, NATIONAL$.

the problem i am having is that after the second sed command, sed finds "NATIONAL" but it renames it as "LOCAL$" instead of "NATIONAL$". Does anyone see an issue with the commands? Any help would be greatly appreciated.

1 Answer 1

4

You're mixing character classes (a list of characters inside square brackets) with the smb.conf share names which are surrounded by square bracket literals. Also, the echo command is not well-formed: in the case where sed exits with a non-zero status, the shell will attempt to invoke the command Failed.

A few suggestions:

  1. Remove the character class (outer brackets)
  2. Remove the leading .* which will remove leading comments, etc.
  3. Run a single sed command with multiple statements
  4. Fix the error case message


sed -i 's/\[CMI\]/\[CMI\$\]/;
        s/\[LOCAL\]/\[LOCAL\$\]/;
        s/\[NATIONAL\]/\[NATIONAL\$\]/' $smbconffile && echo "Success" || echo "Failed"`

You could use backreferences to avoid retyping the original prefix in the replacement expression (e.g., `[CMI'), but that can make the expressions even harder to read.

Another suggest is to use Perl which has readable grouping and backreferences IMO:

perl -pi -e 's/(\[(?:CMI|LOCAL|NATIONAL))\]/$1\$]/g' $smbconffile \
    && echo "Success" || echo "Failed"


Edit: To clarify, the problem with the original expression with the outer brackets is that you are creating a character class which matches any string containing (in the first case) [, C, M, I, ] in any order followed by a ]. For example:

$ echo '[IMC]' | sed 's/[\[CMI\]]/[something_else]/'
[IM[something_else]

$ echo '[FOOM]' | sed 's/[\[CMI\]]/[something_else]/'
[FOO[something_else]

Removing the outer brackets removes the character class so the expression will match the exact substring provided.

3
  • great answer! Your answer fix it! Explained very well with the addition edit. If only I had enough reputation points to reward your answer. Dec 15, 2014 at 22:12
  • 1
    Aditionally sed has no exit code if it is not stated by q or Q sed's actions so the constructions like sed && command || command is void. Instead you can use t or T operations to produce indicator messages.
    – Costas
    Dec 15, 2014 at 22:13
  • @Costas: I observed that sed will exit nonzero on fatal errors such as a missing input file, but did not know about the q or Q actions. Thank you for clarifying.
    – zackse
    Dec 16, 2014 at 14:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .