On Solaris 10, I have several source files similar to file1.cpp, as given below:
// file1.cpp
#include <string>
#include <unordered_map>
void func() {
. . .
}
I would like to insert #include <iostream>
before first #include
(if any): thus, the file would become:
// file1.cpp
#include <iostream>
#include <string>
#include <unordered_map>
void func() {
. . .
}
In case there is no include e.g.
// file1.cpp
void func() {
. . .
}
This will become:
// file1.cpp
#include <iostream>
void func() {
. . .
}
However, if the file already contains #include <iostream>
, the insertion of another #include <iostream>
would be ignored. Thus, if we have,
// file1.cpp
#include <string>
#include <unordered_map>
#include <iostream>
void func() {
. . .
}
It will remain same, i.e.
// file1.cpp
#include <string>
#include <unordered_map>
#include <iostream>
void func() {
. . .
}
My attempt:
bash-3.00$ cat TRYIT
#!/bin/bash
echo \#include \<iostream\> > x$$
for i in `find . -type f -name "*.cpp"`
do
if ! grep -s "\#include \<iostream\>" "$i" > /dev/null; then
sed "/\#include/r x$$" "$i" > "$i".bak
mv "$i".bak "$i"
fi
done
rm x$$
But this does not work as per my requirement, please suggest.
This works OK on Linux, and I believe it should work on Solaris.
File xyz.c
:
/* First line must not start #include */
#include <stdio.h>
#define PERGATORY
#include <meniscus.h>
the real code
Command:
$ sed -e '1,/^[:space:]*#[:space:]*include/ { /^[:space:]*#[:space:]*include/i\
> #include <iostream>
> }' xyz.c
/* First line must not start #include */
#include <iostream>
#include <stdio.h>
#define PERGATORY
#include <meniscus.h>
the real code
$
If you need to deal with files that have a #include
at the start of the first line, it is fiddlier. Without a change, you get #include <iostream>
inserted before line 1 (what was wanted) and also before the first line after line 1 that starts with #include
. With GNU sed
, you can use 0
in place of the 1
and it works well; referencing line 0 is not a POSIX standard feature and probably won't work on Solaris, though.
I'm not sure what's the best workaround without that — probably using awk
instead of sed
is the least difficult (and it works nicely for the first #include
after the first line as well, of course — it is a more general solution):
awk '/^[:space:]*#[:space:]*include/ { if (done++ == 0)
print "#include <iostream>" }
{print}' …filename…
What about if I want to have
iostream
as variable captured in$NM
, i.e.NM=iostream
set earlier in the script? How do I use$NM
within theawk
?
NM="iostream"
awk -v header="$NM" \
'/^[:space:]*#[:space:]*include/ { if (done++ == 0)
printf "#include <%s>\n", header }
{print}' …filename…
The key point is the use of -v variable=value
on the command line to relay the header name to the awk
script, and then modifying the print
into a printf
to format the string correctly (remembering that a newline is needed).