简体   繁体   中英

sed or Perl one liner + how to replace path in file only when full match

We want to replace the path on /etc/fstab file from

/dev/sdb /var/kafka ext4 defaults,noatime 0 0

To ( expected output )

/dev/sdb /var/kafka/hadoop_kafka ext4 defaults,noatime 0 0

The sed syntax that we are wrote is

sed s'/\/var\/kafka/\/var\/kafka\/hadoop_kafka/g' /etc/fstab

so once we run then we get in fstab this

/dev/sdb /var/kafka/hadoop_kafka ext4 defaults,noatime 0 0

But once we run again the sed then we get wrong path in fstab as:

/dev/sdb /var/kafka/hadoop_kafka/hadoop_kafka ext4 defaults,noatime 0 0

So how to replace the path, only in case we match the path:

/var/kafka

The following 'awk' could assist you here

$ awk '($2=="/var/kafka"){$2="/var/kafka/hadoop_kafka"}1' file

The way awk operates is simple, its syntax, on the other hand, might be a bit unusual for the uninitiated. Awk operates on records, which by default are lines, and each record is spllit in fields. By default these fields are separated by a sequence of one or more blanks (spaces, tabs, ...). Per record, awk will process a sequence of pattern-action pairs written in the form (pattern){action} . You can read this very simply is If pattern is true, perform action . The default pattern is true and the default action is print .

When we look at the above we see the following two pattern-action pairs:

  • ($2=="/var/kafka"){$2="/var/kafka/hadoop_kafka"} . This we can translate as: If the second field equals "/var/kafka", then replace the second field with "/var/kafka/hadoop_kafka"
  • 1 : This just says one, which equals to "true" and is a pattern, so we add the default action {print} . So this statement just prints the current line.

With your shown samples/attempts, please try following sed program.

sed -E 's/^([^ ]*\s+)(\/var\/kafka)(\s.*)/\1\2\/hadoop_kafka\3/ Input_file

Explanation: Firstly using -E option of sed to enable ERE(extended regex), then using s option to perform substitution here. In substitution part regex using back references concept(to keep matched values in a temp buffer memory, to be used later on in program).

  • ^([^ ]*\s+) : Matching everything from till 1st occurrence of space comes in 1st capturing group.
  • (\/var\/kafka) : Creating 2nd capturing group which makes sure that it matches /var/kafka in it.
  • (\s.*) : Matching rest of the line here.

While performing substitution adding \/hadoop_kafka after 2nd capturing group as per requirement.

NOTE: Above code will print the values on terminal, once you are Happy with results use -i option to make a inplace save into Input_file.

You may try this sed :

sed -i.bak -E 's~(^|[[:blank:]])/var/kafka([[:blank:]])~\1/var/kafka/hadoop_kafka\2~g' /etc/fstab

RegEx Details:

  • (^|[[:blank:]]) : Match start or a space or tab in capture group #1
  • /var/kafka : Match text /var/kafka
  • ([[:blank:]]) : Match a space or tab in capture group #2
  • \1/var/kafka/hadoop_kafka\2 : In replacement put back value captured in group #1 followed by /var/kafka/hadoop_kafka followed by value captured in group #2
perl -pe's{^\S+\s+/var/kafka\K(?=\s)}{/hadoop_kafka}'

How you'd use it:

perl -i -pe's{^\S+\s+/var/kafka\K(?=\s)}{/hadoop_kafka}' /etc/fstab

You want to replace the second field, which the is between whitespace after the leading sequence of non-whitespace.

s{
   ^ ( \S+ \s+ ) /var/kafka ( \s | $ )
}{
   $1 . "/var/kafka/hadoop_kafka" . $2
}ex

So, you want

perl -pe'
   s{
      ^ ( \S+ \s+ ) /var/kafka ( \s | $ )
   }{
      $1 . "/var/kafka/hadoop_kafka" . $2
   }ex
'

or the equivalent

perl -pe's{^\S+\s+/var/kafka\K(?=\s)}{/hadoop_kafka}'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM