Awk: understanding how comments are removed in php - bash

Apologies in advance for a rather simplistic question.
In a big pile of "note to self", I have this little awk one-liner that works perfectly for my needs, which is to remove comments from a php file. But I would like to better understand it:
awk '/^\/\*/{c++} c!=1; /^ \*\//{c++}'
I cannot, unfortunately, find the original post in order to better understand how it works.
Googling it turns up a ton of things on c++ but not the original post. Neither Explain Shell nor Symbol Hound has helped.
I don't particularly stumped by the {c++} c!=1; bit. Any help would be greatly appreciated.

I have tested your awk script and it does not work properly!!!
You should use the following one to remove :
gawk '/^\/\*/{c++} c!=1; /^.*\*\//{c=0}' php_file
to remove /* comments */ multi-lines comments or single lines with only /* comments */!!!
TESTED on:
In a nutshell,
awk will read the input file line by line and will do its default action: printing
when the condition /^\/\*/ is met ( /* comment that is directly located at the start of the line) the block {c++} will be executed!, in awk variable are by default initiated to 0, so after the block c=1 and c!=1 will be false so nothing will be printed.
as long as we are in the comment section c!=1 will be false so nothing will be printed.
then we reach the last line of comment and c is set back to 0, so from the following line everything will be printed again.
REMARK:
lines with commands followed /* */ are still printed as-is
// comments are not removed
If there are some super important commands on the same line directly following a comment block they will be lost!!!
/* comment starts
/* still some comments
end of comments */some super important commands;
IMPROVEMENT:
change c=!1 by c<1 to improve the stability of the script, with c!=1 your script will stop functioning properly in the case:
/* comment starts
/* still some comments
end of comments */

Related

Remove all comments from a bash script

I came across this interesting snippet of code that removes comments from a bash script, and I have some uses for it so I keep it in my .bashrc
alias decomment='egrep -v "^[[:space:]]*((#|;|//).*)?$" '
However, it only strips lines that start with a comment. Is there a way to extend this code so that it can also strip comments at the end of lines. e.g. lines like this:
MyVariable=stuff # This is my variable

Way to create multiline comments in Bash?

I have recently started studying shell script and I'd like to be able to comment out a set of lines in a shell script. I mean like it is in case of C/Java :
/* comment1
comment2
comment3
*/`
How could I do that?
Use : ' to open and ' to close.
For example:
: '
This is a
very neat comment
in bash
'
Multiline comment in bash
: <<'END_COMMENT'
This is a heredoc (<<) redirected to a NOP command (:).
The single quotes around END_COMMENT are important,
because it disables variable resolving and command resolving
within these lines. Without the single-quotes around END_COMMENT,
the following two $() `` commands would get executed:
$(gibberish command)
`rm -fr mydir`
comment1
comment2
comment3
END_COMMENT
Note: I updated this answer based on comments and other answers, so comments prior to May 22nd 2020 may no longer apply. Also I noticed today that some IDE's like VS Code and PyCharm do not recognize a HEREDOC marker that contains spaces, whereas bash has no problem with it, so I'm updating this answer again.
Bash does not provide a builtin syntax for multi-line comment but there are hacks using existing bash syntax that "happen to work now".
Personally I think the simplest (ie least noisy, least weird, easiest to type, most explicit) is to use a quoted HEREDOC, but make it obvious what you are doing, and use the same HEREDOC marker everywhere:
<<'###BLOCK-COMMENT'
line 1
line 2
line 3
line 4
###BLOCK-COMMENT
Single-quoting the HEREDOC marker avoids some shell parsing side-effects, such as weird subsitutions that would cause crash or output, and even parsing of the marker itself. So the single-quotes give you more freedom on the open-close comment marker.
For example the following uses a triple hash which kind of suggests multi-line comment in bash. This would crash the script if the single quotes were absent. Even if you remove ###, the FOO{} would crash the script (or cause bad substitution to be printed if no set -e) if it weren't for the single quotes:
set -e
<<'###BLOCK-COMMENT'
something something ${FOO{}} something
more comment
###BLOCK-COMMENT
ls
You could of course just use
set -e
<<'###'
something something ${FOO{}} something
more comment
###
ls
but the intent of this is definitely less clear to a reader unfamiliar with this trickery.
Note my original answer used '### BLOCK COMMENT', which is fine if you use vanilla vi/vim but today I noticed that PyCharm and VS Code don't recognize the closing marker if it has spaces.
Nowadays any good editor allows you to press ctrl-/ or similar, to un/comment the selection. Everyone definitely understands this:
# something something ${FOO{}} something
# more comment
# yet another line of comment
although admittedly, this is not nearly as convenient as the block comment above if you want to re-fill your paragraphs.
There are surely other techniques, but there doesn't seem to be a "conventional" way to do it. It would be nice if ###> and ###< could be added to bash to indicate start and end of comment block, seems like it could be pretty straightforward.
After reading the other answers here I came up with the below, which IMHO makes it really clear it's a comment. Especially suitable for in-script usage info:
<< ////
Usage:
This script launches a spaceship to the moon. It's doing so by
leveraging the power of the Fifth Element, AKA Leeloo.
Will only work if you're Bruce Willis or a relative of Milla Jovovich.
////
As a programmer, the sequence of slashes immediately registers in my brain as a comment (even though slashes are normally used for line comments).
Of course, "////" is just a string; the number of slashes in the prefix and the suffix must be equal.
I tried the chosen answer, but found when I ran a shell script having it, the whole thing was getting printed to screen (similar to how jupyter notebooks print out everything in '''xx''' quotes) and there was an error message at end. It wasn't doing anything, but: scary. Then I realised while editing it that single-quotes can span multiple lines. So.. lets just assign the block to a variable.
x='
echo "these lines will all become comments."
echo "just make sure you don_t use single-quotes!"
ls -l
date
'
what's your opinion on this one?
function giveitauniquename()
{
so this is a comment
echo "there's no need to further escape apostrophes/etc if you are commenting your code this way"
the drawback is it will be stored in memory as a function as long as your script runs unless you explicitly unset it
only valid-ish bash allowed inside for instance these would not work without the "pound" signs:
1, for #((
2, this #wouldn't work either
function giveitadifferentuniquename()
{
echo nestable
}
}
Here's how I do multiline comments in bash.
This mechanism has two advantages that I appreciate. One is that comments can be nested. The other is that blocks can be enabled by simply commenting out the initiating line.
#!/bin/bash
# : <<'####.block.A'
echo "foo {" 1>&2
fn data1
echo "foo }" 1>&2
: <<'####.block.B'
fn data2 || exit
exit 1
####.block.B
echo "can't happen" 1>&2
####.block.A
In the example above the "B" block is commented out, but the parts of the "A" block that are not the "B" block are not commented out.
Running that example will produce this output:
foo {
./example: line 5: fn: command not found
foo }
can't happen
Simple solution, not much smart:
Temporarily block a part of a script:
if false; then
while you respect syntax a bit, please
do write here (almost) whatever you want.
but when you are
done # write
fi
A bit sophisticated version:
time_of_debug=false # Let's set this variable at the beginning of a script
if $time_of_debug; then # in a middle of the script
echo I keep this code aside until there is the time of debug!
fi
in plain bash
to comment out
a block of code
i do
:||{
block
of code
}

Substitution of substring doesn't work in bash (tried sed, ${a/b/c/})

Before to write, of course I read many other similar cases. Example I used #!/bin/bash instead of #!/bin/sh
I have a very simple script that reads lines from a template file and wants to replace some keywords with real data. Example the string <NAME> will be replaced with a real name. In the example I want to replace it with the word Giuseppe. I tried 2 solutions but they don't work.
#!/bin/bash
#read the template and change variable information
while read LINE
do
sed 'LINE/<NAME>/Giuseppe' #error: sed: -e expression #1, char 2: extra characters after command
${LINE/<NAME>/Giuseppe} #error: WORD(*) command not found
done < template_mail.txt
(*) WORD is the first word found in the line
I am sorry if the question is too basic, but I cannot see the error and the error message is not helping.
EDIT1:
The input file should not be changed, i want to use it for every mail. Every time i read it, i will change with a different name according to the receiver.
EDIT2:
Thanks your answers i am closer to the solution. My example was a simplified case, but i want to change also other data. I want to do multiple substitutions to the same string, but BASH allows me only to make one substitution. In all programming languages i used, i was able to substitute from a string, but BASH makes this very difficult for me. The following lines don't work:
CUSTOM_MAIL=$(sed 's/<NAME>/Giuseppe/' template_mail.txt) # from file it's ok
CUSTOM_MAIL=$(sed 's/<VALUE>/30/' CUSTOM_MAIL) # from variable doesn't work
I want to modify CUSTOM_MAIL a few times in order to include a few real informations.
CUSTOM_MAIL=$(sed 's/<VALUE1>/value1/' template_mail.txt)
${CUSTOM_MAIL/'<VALUE2>'/'value2'}
${CUSTOM_MAIL/'<VALUE3>'/'value3'}
${CUSTOM_MAIL/'<VALUE4>'/'value4'}
What's the way?
No need to do the loop manually. sed command itself runs the expression on each line of provided file:
sed 's/<NAME>/Giuseppe/' template_mail.txt > output_file.txt
You might need g modifier if there are more appearances of the <NAME> string on one line: s/<NAME>/Giuseppe/g

Remove block-comments from a file with a bash script

There is a way to remove from a file all rows wrapped between /* and */ using a bash script?
I use percona to generate a sql script to syncronize two databases, a development one to a production one. Percona generates a well formatted SQL script but full of comments which make increase file size. So, just to make easier upload operation I'd prefer to remove all the unnecessary.
EDIT ON January 10th
I solved with this code:
sed -r ':a; s%(.*)/\*.*\*/%\1%; ta; /\/\*/ !b; N; ba' <FILE_TO_CLEAN>
thanks all
Using sed:
sed '/\/\*.*\*\// d; /\/\*/,/\*\// d' file
The command d tells sed to delete patterns matching the preceeding expression. The first expression /\/\*.*\*\// matches one-line comments, the second one /\/\*/,/\*\// comments that range multiple lines (this is implied by the ,).
I don't know if this works 100%, but as far as I tried, it did the job.
-Try this script- it should help removing the comments, since are the same as C++ Here you can see another sed example to remove HTML comments

How do I set new line with a sed using c\?

I am feeling stupid but have tried multiple ways of having new line in my script. I got help from Jonathan with a sed command. It worked great but the formatting is lost and now I can't find a way to make it work.
The code looks like this:
su -c "sed -i '/aStyle.Landscape {/,/}/c\
MImAbstractKeyAreaStyle.Landscape {\
/*** Label Setttings ***/\
label-margin-top: 10.6mm; /* 0.6 */\
label-margin-left-with-secondary: -1; /* not used, labels are centered horizontally */\
secondary-label-separation: 0;\
...
/*** Key Area Geometry ***/\
size: 854 -1;\
}' file.css"
I wanted to substitute a paragraph with another one. But with this command everything are printed on one line. I want it to keep the formatting. My original question is here: How to substitute a paragraph in file?
First try without the su -c. Between your "" quotes, the escaping is different and make it much more complicated.
When you're done, either put the result in a script file and call that with su -c ./script.sh, or adapt the escaping (but that's never gonna be nice).
This might work for you:
echo hello | sed '/.*/c\This first line is no longer "hello"\nand this is the second line\nand this the third line'
This first line is no longer "hello"
and this is the second line
and this the third line
In GNU sed you can embed the newlines \n but please see my amended answer to you last question (using a here-document) for a WYSIWYG answer.

Resources