ChatGPT解决这个技术问题 Extra ChatGPT

How to UNCOMMENT a line that contains a specific string using Sed?

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.

sed -i '/ 2001 /s/^#//' file may be?
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}}).

J
JNLK

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.


add the -e argument for macOS and BSD
To avoid commenting multiple times and taking into account multiple leading #, use the following commands: sed -i '/<pattern>/s/^#*/#/g' file (to comment out) and sed -i '/<pattern>/s/^#*//g' file (to uncomment)
Thanks jnlk and @louis-m. This solution is what worked best for me and accounting for multiple # characters works perfectly.
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 '/<pattern>/s/^#*\s*//g' file
this should be the accepted answer IMHO, well explained.
A
Avinash Raj

Try this sed command,

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

why . that will remove the first character even if its not a comment ?
still needs to be fail proof. this answer needs corrections if it is to be chosen
You can tighten the line-matching regex to /^#.* 2001 /, but what you've got is strictly within the remit of the question.
Make it fail proof. must uncomment only if it is commented.
Oh, you're the op. So what's your actual file content?
C
Community

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.


M
Mike Q

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

m
max4ever

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