2 bug fix: the sed command would not write out the new line if the old file ended with a /swapfile line
source | link

You can do this with sed — it's Turing-complete. But it isn't the best tool for the job. Sed doesn't have a convenient way of remembering that it's already made a replacement.

What you can relatively easily do with sed is to removeblank all the lines starting /swapfile, and add a new one at the end:

sed -i ''$! s/^\/swapfile[\t ]/d;/; $s/\(^\/swapfile.*\)\?$/\n\/swapfile none swap sw/' /etc/fstab

but beyond that we're quickly getting into territory where I wouldn't leave such sed code for another sysadmin to maintain, especially when a simple, readable combination of shell commands would do a better job:

{ </etc/fstab grep -v '/swapfile[\t ]'; echo '/swapfile none swap sw'; } >/etc/fstab.new && mv /etc/fstab.new /etc/fstab

If you want to preserve the existing position of the /swapfile line if it's there and only modify the file if it needs modifying, a combination of shell logic and awk is a better tool. I've used multiple lines here for clarity but you can put all the code on the same line if you like. As a bonus, if the file already contained the intended line (with exact spacing), it won't be modified.

awk '
  /\/swapfile[\t ]/ {if (replaced) {next}
                     else {replaced=1; print "/swapfile none swap sw"}}
  1 {print}
  END {if (!replaced) print "/swapfile none swap sw"}
' /etc/fstab >/etc/fstab.new &&
if cmp -s /etc/fstab.new /etc/fstab.new; then
  rm /etc/fstab.new;
else
  mv /etc/fstab.new /etc/fstab;
fi

You can do this with sed — it's Turing-complete. But it isn't the best tool for the job. Sed doesn't have a convenient way of remembering that it's already made a replacement.

What you can easily do with sed is to remove all the lines starting /swapfile, and add a new one at the end:

sed -i '/^\/swapfile[\t ]/d; $s/$/\n\/swapfile none swap sw/' /etc/fstab

If you want to preserve the existing position of the /swapfile line if it's there and only modify the file if it needs modifying, a combination of shell logic and awk is a better tool. I've used multiple lines here for clarity but you can put all the code on the same line if you like. As a bonus, if the file already contained the intended line (with exact spacing), it won't be modified.

awk '
  /\/swapfile[\t ]/ {if (replaced) {next}
                     else {replaced=1; print "/swapfile none swap sw"}}
  1 {print}
  END {if (!replaced) print "/swapfile none swap sw"}
' /etc/fstab >/etc/fstab.new &&
if cmp -s /etc/fstab.new /etc/fstab.new; then
  rm /etc/fstab.new;
else
  mv /etc/fstab.new /etc/fstab;
fi

You can do this with sed — it's Turing-complete. But it isn't the best tool for the job. Sed doesn't have a convenient way of remembering that it's already made a replacement.

What you can relatively easily do with sed is to blank all the lines starting /swapfile, and add a new one at the end:

sed -i '$! s/^\/swapfile[\t ]//; $s/\(^\/swapfile.*\)\?$/\n\/swapfile none swap sw/' /etc/fstab

but beyond that we're quickly getting into territory where I wouldn't leave such sed code for another sysadmin to maintain, especially when a simple, readable combination of shell commands would do a better job:

{ </etc/fstab grep -v '/swapfile[\t ]'; echo '/swapfile none swap sw'; } >/etc/fstab.new && mv /etc/fstab.new /etc/fstab

If you want to preserve the existing position of the /swapfile line if it's there and only modify the file if it needs modifying, a combination of shell logic and awk is a better tool. I've used multiple lines here for clarity but you can put all the code on the same line if you like. As a bonus, if the file already contained the intended line (with exact spacing), it won't be modified.

awk '
  /\/swapfile[\t ]/ {if (replaced) {next}
                     else {replaced=1; print "/swapfile none swap sw"}}
  1 {print}
  END {if (!replaced) print "/swapfile none swap sw"}
' /etc/fstab >/etc/fstab.new &&
if cmp -s /etc/fstab.new /etc/fstab.new; then
  rm /etc/fstab.new;
else
  mv /etc/fstab.new /etc/fstab;
fi
1
source | link

You can do this with sed — it's Turing-complete. But it isn't the best tool for the job. Sed doesn't have a convenient way of remembering that it's already made a replacement.

What you can easily do with sed is to remove all the lines starting /swapfile, and add a new one at the end:

sed -i '/^\/swapfile[\t ]/d; $s/$/\n\/swapfile none swap sw/' /etc/fstab

If you want to preserve the existing position of the /swapfile line if it's there and only modify the file if it needs modifying, a combination of shell logic and awk is a better tool. I've used multiple lines here for clarity but you can put all the code on the same line if you like. As a bonus, if the file already contained the intended line (with exact spacing), it won't be modified.

awk '
  /\/swapfile[\t ]/ {if (replaced) {next}
                     else {replaced=1; print "/swapfile none swap sw"}}
  1 {print}
  END {if (!replaced) print "/swapfile none swap sw"}
' /etc/fstab >/etc/fstab.new &&
if cmp -s /etc/fstab.new /etc/fstab.new; then
  rm /etc/fstab.new;
else
  mv /etc/fstab.new /etc/fstab;
fi