ARao
ARao

Reputation: 259

sed replace fails to replace string in if there's a square bracket

My result variable contains the following:

auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=888
auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=888

I want to replace the entire lines and I'm using sed. The replace seems to work okay fir first iteration but not second one. However, when I print the values, it shows that the new value is correctly updated.

echo "$result" |
   while IFS= read -r line;
   do
      newValue=""
      for ii in $line
      do
         if [[ "$ii" != *"unlock_time"* ]]; then
            newValue="$newValue $ii"
         fi
      done
      newValue="$newValue unlock_time=900"
      sed -i "s/$line/$newValue/g" $password_auth
      echo " Line    : [ $line ]"
      echo "newValue : [ $newValue ]"
   done

The output shows this:

 Line    : [  auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=900 ]
newValue : [  auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=900 ]
 Line    : [ auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=888 ]
newValue : [  auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=900 ]

Here when it is displaying I see that the correct value is present in the variables and all the prints take place after sed command and I see no errors before prints in output.

But when I check the file, I see the second instance of unlock_time is still 888 instead of 900.

Note: I cannot globally replace unlock_time which is why I'm storing the lines that need updating in result.

Is there anything that is overlooked in the loop?

Update: I've tried running the sed commands on command line:

sed -i "s/auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=900/auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=999/g" temp  <-- This works
sed -i "s/auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=9/auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=900/g" temp   <-- This doesn't update file but doesn't throw an error either

The command works on command line when I put escape characters around [default=die]. But how do I do it if I'm doing it through script?

Upvotes: 0

Views: 322

Answers (1)

jhnc
jhnc

Reputation: 16868

You are trying to find a constant. The regexp matching through layers of quoting is getting in the way. Here's a simpler perl method (wrapped in bash for demo purposes):

#!/bin/bash

result="auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=888
auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=888"

# create a file to play with
echo "$result" > testfile

echo "$result" | perl -i -pe '
    BEGIN { @find = <STDIN> }
    for $str (@find) {
        s/(\bunlock_time)=\d+/$1=900/ if $_ eq $str;
    }
' testfile

# check the result
cat testfile
  • -i does inplace editing like sed
  • -p wraps a while loop to read each line so an explicit one isn't needed and prints out the line after possible modification (a bit like sed)
  • the BEGIN section initialises the array of strings to look for (from result)
  • for each line of testfile ($_), for compares it against all the strings, and if there is a literal match (eq), does a regexp search&replace on the unlock_time parameter

Upvotes: 1

Related Questions