How to use a variable command in a sed expression

65 Views Asked by At

Testing for a simple script but I can't get this variable to cooperate with me. I've tried so many things, single quotes and doubles.

New=$(df -h)

sed -ie "200s|^.*$|"${NEW}"|g" "file.txt"

I'm trying to replace whatever is on line 200 of file.txt with the output of df -h pretty much.

Need help, if this has been asked before, sorry my brain is toasted and I'm not smart enough to comprehend.

most of the time i get an "unterminated `s'" error when I run the script. I'm thinking it's got something to do with the "{}" brackets around the variable and it being misread as something else in regex.

3

There are 3 best solutions below

6
tjm3772 On

The output of df -h has whitespace so you need to keep it quoted to prevent word splitting. Compare:

# wrong - ${NEW} is not inside the quotes on either its left or right hand sides 
sed -ie "200s|^.*$|"${NEW}"|g" "file.txt" 
# better - ${NEW} is within the double-quoted string
sed -ie "200s|^.*$|${NEW}|g" "file.txt"
# if ${NEW} contains newlines
sed -ie "200s|^.*$|${NEW//$'\n'/\\$'\n'}|g" "file.txt"

awk could be more readable/maintainable here as you don't have to interpolate the data into the command string:

awk -v subststr="${NEW}" -v lineno=200 '
  { if (NR == lineno) { print subststr } else {print $0} }
' file.txt > output.txt && mv output.txt file.txt
0
pjh On

It is possible to reliably escape variable values so they can be used in sed substitutions. See Is it possible to escape regex metacharacters reliably with sed and Escape a string for a sed replace pattern.

If your input file is small (up to a megabyte should be OK on any modern system) and you've got Bash 4.0 (released in 2009) or later, there is an easy way to do what you want with pure Bash. Try this Shellcheck-clean code:

#! /bin/bash -p

readarray -O 1 -t lines <file.txt
lines[200]=$(df -h)
printf '%s\n' "${lines[@]}" >file.txt
0
chepner On

I would use ed instead, especially if you haven't already executed df -h, because you can read the output directly into the file without an intermediate shell variable.

ed file.txt <<EOF
200r !df -h
200d
wq
EOF

The output of df -h is inserted between lines 200 and 201, and then line 200 is deleted.