70

The lines in the file :

-A INPUT -m state --state NEW -m tcp -p tcp --dport 2000 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 2001 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 2002 -j ACCEPT

to comment out let's say the line that contains

2001

i can simply run this SED command:

sed -i '/ 2001 /s/^/#/' file

but now how do i revert back ?

as in uncomment that same line ?

i tried

sed -i '/ 2001 /s/^//' file

that does not work.

jww
  • 97,681
  • 90
  • 411
  • 885
  • 5
    `sed -i '/ 2001 /s/^#//' file` may be? – jaypal singh Jul 22 '14 at 13:55
  • 1
    Why are you using this technique? The standard technique would be to use one line in the script and make the year number into an argument to the script. You could even default to, say, 2001 if no argument is provided (`${1:-2001}`), or use an environment variable (`${DEFAULT_YEAR:-2001}`), or both (`${1:-${DEFAULT_YEAR:-2001}}`). – Jonathan Leffler Jul 22 '14 at 14:07

5 Answers5

137

Yes, to comment line containing specific string with sed, simply do:

sed -i '/<pattern>/s/^/#/g' file

And to uncomment it:

sed -i '/<pattern>/s/^#//g' file

In your case:

sed -i '/2001/s/^/#/g' file    (to comment out)
sed -i '/2001/s/^#//g' file    (to uncomment)

Option "g" at the end means global change. If you want to change only a single instance of pattern, just skip this.

JNLK
  • 1,688
  • 2
  • 12
  • 10
  • 1
    add the `-e` argument for macOS and BSD – Jonas Feb 25 '17 at 10:55
  • 15
    To avoid commenting multiple times and taking into account multiple leading `#`, use the following commands: `sed -i '//s/^#*/#/g' file (to comment out)` and `sed -i '//s/^#*//g' file (to uncomment)` – Louis M May 02 '17 at 11:46
  • Thanks jnlk and @louis-m. This solution is what worked best for me and accounting for multiple # characters works perfectly. – grt3kl Jul 20 '18 at 13:35
  • 5
    And if you want to make sure there is no whitespace at the start of line (e. g. in `# This is commented out` you can use `sed -i '//s/^#*\s*//g' file` – smoothware Jan 03 '19 at 20:10
  • 1
    this should be the accepted answer IMHO, well explained. – Viktova May 09 '19 at 10:32
  • best answer. thk – acgbox Mar 16 '20 at 17:35
  • Why is it working? Where is `s/pattern/replacement/flags`???? :D – Dims Mar 24 '21 at 10:50
  • @smoothware this doesn't work if whitespace is before `#`. Instead use: `sed -i '//s/^[#[:space:]]*/#/g' file` to comment out, `sed -i '//s/^[#[:space:]]*//g' file` to uncomment – morrow Jan 25 '22 at 20:32
  • And use `sed -i_BKP-$(date -I) ...` to make a copy with a timestamp on the fly – Pablo Bianchi Jun 21 '23 at 20:59
56

Try this sed command,

sed -i '/^#.* 2001 /s/^#//' file
Avinash Raj
  • 172,303
  • 28
  • 230
  • 274
6

To complement @Avinash Raj's helpful answer with a more generic, POSIX-compliant solution.

  • Toggles commenting of lines that match a specifiable string that must occur as a separate word anywhere on the line.
  • The comment character (string) is also specifiable.

Note that the solution is awk-based, because a robust portable solution with sed is virtually impossible due to the limitations of POSIX' basic regular expressions.

awk -v commentId='#' -v word='2001' '
  $0 ~ "(^|[[:punct:][:space:]])" word "($|[[:punct:][:space:]])" { 
    if (match($0, "^[[:space:]]*" commentId))
      $0 = substr($0, RSTART + RLENGTH)
    else
      $0 = commentId $0
  } 
  { print }
  ' file > tmpfile.$$ && mv tmpfile.$$ file
  • (^|[[:punct:][:space:]]) and ($|[[:punct:][:space:]]) are the POSIX extended regex equivalents of the \< and \> word-boundary assertions known from other regex dialects.
  • Whitespace after the comment char is preserved, but not before it.
  • When prepending the comment char to a line, it is directly prepended, without whitespace.
  • Thus, if you only toggle comments with this solution, all whitespace is preserved.
  • POSIX awk doesn't offer in-place updating (neither does POSIX sed, incidentally), hence the output is first captured in a temporary file and that file then replaces the original on success.
Community
  • 1
  • 1
mklement0
  • 382,024
  • 64
  • 607
  • 775
2

Quick example of how to comment and uncomment a line in a file.

Sample file :

umask 027
TMOUT=600

Lets now backup the file (just for laughs) and comment out and un comment:

# backup file (because we should always do this)
cp /etc/bash.bashrc /etc/bash.bashrc.$(date '+%Y-%m-%d,%H:%M:%S')

# original: TMOUT=600   , result :# TMOUT=600
sed -i '/[^#]/ s/\(^TMOUT=600.*$\)/#\ \1/' /etc/bash.bashrc

# original # TMOUT=600   ,result :TMOUT=600
sed -i '/^#.*TMOUT=600.*$/s/^#\ //' /etc/bash.bashrc
Mike Q
  • 6,716
  • 5
  • 55
  • 62
0

For mac, which doesn't support standard sed parameters, this would remove the hashtag

sed -i "" "/.*#.*d\/docker-php-ext-xdebug\.ini.*/s/^#//g" docker-compose.yml
max4ever
  • 11,909
  • 13
  • 77
  • 115