Home > Back-end >  Replacing the value of specific field in a table-like string stored as bash variable
Replacing the value of specific field in a table-like string stored as bash variable

Time:07-02

I am looking for a way to replace (with 0) a specific value (1043252782) in a "table-like" string stored as a bash variable. The output of echo "$var"looks like this:

  5 Reallocated_Sector_Ct   0x0033   100   100   010    Pre-fail  Always       -       0
  7 Seek_Error_Rate         0x000f   090   060   045    Pre-fail  Always       -       1043252782
 10 Spin_Retry_Count        0x0013   100   100   097    Pre-fail  Always       -       0
187 Reported_Uncorrect      0x0032   100   100   000    Old_age   Always       -       0

After the replacement echo "$var" should look like this:

  5 Reallocated_Sector_Ct   0x0033   100   100   010    Pre-fail  Always       -       0
  7 Seek_Error_Rate         0x000f   090   060   045    Pre-fail  Always       -       0
 10 Spin_Retry_Count        0x0013   100   100   097    Pre-fail  Always       -       0    
187 Reported_Uncorrect      0x0032   100   100   000    Old_age   Always       -       0

Is there a way to do this without saving the content of $var to a file and directly manipulating it within the bash (shell script)?

Maby with awk? I can select the value in the 10th field of the second record with awk and pattern matching ("7 Seek_Error_Rate ....") like this:

echo "$var" | awk '/^  7/{print $10}'

Maby there is some way doing it with awk (or other cli-tool) to replace it and store it back into $var? Also, the value changes over time, but the structure remains the same (some record at the 10th field).

Cheers!

CodePudding user response:

You can change a specific string directly in the shell:

var=${var/1043252782/0}

To replace final number of second line, you could use awk or sed:

var=$(awk 'NR==2 { sub(/[0-9] $/,0) }1' <<<"$var")
var=$(sed '2s/[0-9][0-9]*$/0/' <<<"$var")

If you don't know which line it will be, you can match a known string:

var=$(awk '/Seek_Error_Rate/{ sub(/[0-9] $/,0) }1' <<<"$var")
var=$(sed '/Seek_Error_Rate/s/[0-9][0-9]*$/0/' <<<"$var")

CodePudding user response:

You can use a here-string to feed the variable as input to awk.

Use sub() to perform a regular expression replacement.

var=$(awk '{sub(/1043252782$/, "0")}1' <<<"$var")

CodePudding user response:

Using sed

$ var=$(sed '/1043252782$/s//0/' <<< "$var")
$ echo "$var"
  5 Reallocated_Sector_Ct   0x0033   100   100   010    Pre-fail  Always       -       0
  7 Seek_Error_Rate         0x000f   090   060   045    Pre-fail  Always       -       0
 10 Spin_Retry_Count        0x0013   100   100   097    Pre-fail  Always       -       0
187 Reported_Uncorrect      0x0032   100   100   000    Old_age   Always       -       0

CodePudding user response:

If you don't care about the indentation of the target line then awk might be the most readable, and also simple enough:

var=$(awk '$1 == 7 {$10 = 0} 1' <<< "$var")

If you do care about indentation then you can use a regex for replacing the last field of the target line:

awk '$1 == 7 {sub(/[^ ] $/,"0")} 1'
# or
sed -E '/^  7/s/[^ ] $/0/'

Aside: I understand that the Seek_Error_Rate isn't very useful, but if you have a bunch of HDDs of the same model then you can detect a sub-performing one by comparing this attribute value.

CodePudding user response:

if you don't wanna ruin formatting of tabs and spaces :

{m,g}wk NF=NF FS=' 1043252782$' OFS=' 0' :

  5 Reallocated_Sector_Ct   0x0033   100   100   010    Pre-fail  Always       -       0
  7 Seek_Error_Rate         0x000f   090   060   045    Pre-fail  Always       -       0
 10 Spin_Retry_Count        0x0013   100   100   097    Pre-fail  Always       -       0
187 Reported_Uncorrect      0x0032   100   100   000    Old_age   Always       -       0

or doing the whole file in one single shot :

  • awk NF=NF FS=' 1043252782\n' OFS=' 0\n' RS='^$' ORS=

  • awk NF=NF FS=' 1043252782\n' OFS=' 0\n' RS= -- (This might work too but I'm not too well versed in any side effects for blank RS)

  • Related