Home > OS >  how to insert text in matching line only and only if not already present for bash
how to insert text in matching line only and only if not already present for bash

Time:03-16

Trying to search /etc/pam.d/common-password file for entry that starts with password required pam_unix.so and check to see if sha512 is in the fourth column. If its there, do nothing. If its not there add it. It could be anywhere in the fourth column, but it seems easiest to add to the end if not there.

password        required        pam_unix.so     use_authtok nullok shadow try_first_pass

So ending line should look like:

password        required        pam_unix.so     use_authtok nullok shadow try_first_pass sha512

Using the below if statement and replacing the comment with my command:

if [[ "$(grep  'password'$'\t''required'$'\t''pam_unix.so' common-password | cut -f4)" != *"sha512"* ]]; then
    >&2 echo 'Remediation needs to be done'
fi

Tried below awk but end up with an empty common-password file

awk '/^'password'$'\t''required'$'\t''pam_unix.so'/{print $0," sha512"}' /etc/pam.d/common-password > /etc/pam.d/common-password.fixed && mv /etc/pam.d/common-password.fixed /etc/pam.d/common-password

Tried below grep and sed, but get error "sed: no input files"

grep -F 'password'$'\t''required'$'\t''pam_unix.so' /etc/pam.d/common-password | sed --follow-symlinks -ie 's/$/& sha512/g'

Need to be able to find this line and modify it and only this line. And only if it has not already been modified. I only want to modify this one line if it exists and leave the rest of the file intact.

Any help would be greatly appreciated.

CodePudding user response:

If you can use gnu-awk you can make use of -i inplace and set the field separator and the output field separator to a tab to compare the field values.

Then you can check if field 4 does not contain sha512 using $4 !~ /sha512/

For example

awk -i inplace '
BEGIN{FS=OFS="\t"}
$1=="password" && $2=="required" &&  $3=="pam_unix.so" &&  $4 !~ /sha512/{$0 = $0 OFS "sha512"}1
' file

CodePudding user response:

For one line, use vi and save yourself the trouble of fixing the mess a typo will make.

If you really need an automated edit, simplify to one executable and consolidate your logic.

$: sed -i '/password\trequired\tpam_unix.so\t/{ /\tsha512/{n}; s/$/\tsha512/; }' file

this:

  1. searches for records that have the initial required string of password\trequired\tpam_unix.so\t
  2. opens a block that groups statements to be executed collectively in {...}
  3. searches for records to exclude with /\tsha512/{n}; the n goes on to the next record and skips the rest of the steps in the outer block. This will still output the record, so it won't be deleted from the file on the in-place edit (use d for that).
  4. if the previous check did not match, the n won't be executed, so the next command substitutes in the string you want at the end of the record.
  5. the closing brace of the outer block ends the set of commands on the only outer scan, so sed proceeds to the next record.

If the end-of-record tab logic is not an issue, and you are sure there are no trailing tabs otherwise, or if you are confident that they indicate an empty final field, just use 's/$/\tsha512/', but if it's possible there might be trash tabs at the end of the record, you might want to clean those - maybe 's/\t*$/\tsha512/', or even 's/\t{0,1}$/\tsha512/'. Check your file and your logic against the possible consequences of carelessly editing...

Good luck.

  • Related