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.

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.

  • great answer! Your answer fix it! Explained very well with the addition edit. If only I had enough reputation points to reward your answer. – Matt Pedigo Dec 15 '14 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 '14 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 '14 at 14:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.