sed command to write the name of file to HTML comment - sed

I'm looking for a sed command that, with find, I can take a directory tree of JSP files and write the name of the file in an HTML comment to the top of the file.
This will allow me to review a legacy application JSP call tree of in the HTML source.
I'm thinking it will be a one liner for a talented sed guru...
something like:
find . -name '.jsp' -exec sed ? ? ? {} \;
Maybe something using xargs is more appropriate, but I think sed is the tool that will do the work.

If you want to use sed, you can try
find -name "*.jsp" -exec sed -i '1i <!-- {} -->' {} \;
Works fine for me in the presence of /.

On Unix the filename will contain slashes (/) which are special characters for sed, so I would recommend this simpler approach that writes the filename at the bottom of the file:
find . -name '*.jsp' -exec sh -c "echo '<\!-- {} -->' >> '{}'" \;
To write the filename at the top of the file use this:
find . -name '*.jsp' -exec sh -c \
'echo "<!-- {} -->" > "{}.new" && cat "{}" >> "{}.new" && mv "{}.new" "{}"' \;
N.B. The filename might contain characters that might render your HTML invalid, e.g. &, although I doubt that a JSP could have such a strange name.

Related

No such file or directory when using sed in combination with find?

I am trying to run a script which corrects line breaks in all PHP files. This is how it looks like:
find . -type f -name \*.php -print -exec sed -i '' 's/\r//' {} \;
The errors I get for all files is:
./downloader/lib/Mage/Backup/Exception/SomeFile.php sed: can't read
s/\r//: No such file or directory
Whats the error in the script?
Thanks
The problem is on -i, it depends on the OS you use.
sed -i '' 's/\r//' {}
On macOS, sed expects the file extension to use for the backup file as a separate argument, following -i. An empty string, as you use, tells it to not create a backup file.
On Linux, sed expects the file extension to be joined together with -i in a single argument. For example, -i.bak to append .bak to the file name to generate the name of the backup file or -i to not create a backup file.
Since you get an error that says that the file 's/\r//' does not exist it means that you are using Linux and '' is interpreted as the sed program.
Remove '' and it should work:
sed -i 's/\r//' {}
You can do the following:
find . -type f -name \*.php -print -exec sed -i 's/\r//' {} \;
The issue is sed is expecting sed -i <substitution_pattern> <file>. In your incantation, the '' is interpreted as the substitution pattern, then the 's/\r//' is being interpreted as the file

Using sed to find and delete across multiple files recursively

How can I do a string match against, for example:
<meta name="keywords" content="
Then delete that whole line every time a match is found?
I'm looking to do this for all files in the current directory and below.
I'm also new to sed.
Try this command:
find . -type f -exec sed -i '/foobar/d' {} \;
Change foobar to what you search for.
In answer to the question: "How do I do x to all files recursively?", the answer is to use find. To use sed to delete a line, you can either use the non-portable -i, or simply write a script to redirect the stream. For example:
find . -exec sh -c 'f=/tmp/t.$$;
sed "/<meta name=\"keywords\" content=\"/d" $0 > $f; mv $f $0' {} \;

sed over multiple files in multiple directories

I have the following directory tree:
books>book(i)>cluster.pir
where book(i) are a set of sub directories 1 to 1023 each containing a folder called cluster.pir.
The following sed command:
sed -i '/>/d' ./*.pir
will delete any line in the file containing '>' for any file with a .pir ext, which is great, but my various .pir files are located in their own book(i) directory. How do I get the command to span across all the directories? I have tried:
find ./*.pir -type f -exec sed -i '/>/d' ./*.pir
when starting in the 'book' parent directory, but I get:
find: missing argument to `-exec'
does anyone have any thoughts on this?
Thanks.
The format for find is:
find -exec command {} \;
Where {} is replaced by the filename.
Edit: In your case this would become:
find ./*.pir -type f -exec sed -i '/>/d' {} \;
This will call sed on every file.
You can add a wildcard to span all directories:
sed -i '/>/d' ./book*/*.pir
I was having trouble using file wild-cards with sed on my Mac and this method worked fine:
FILE_PATH="/some/path/"
sed -i '' "s|search|replace|g" $(find ${FILE_PATH} -name '*.ext')

Sed not working with find command

I'm trying to run this sed script on all the files in a directory:
sed.s:
/<constants>/a\
<const type="profElem" name="mission_description" value="NCEP and NCAR Reanalysis Monthly Means and Other Derived Variables"/>
but whenever I run:
find . -exec sed -f sed.s -i {} \;
I get the error:
sed: -i may not be used with stdin
How do I get this to work?
It appears that your version of sed requires you to pass an extension for backups to the -i option. If you feel pretty confident in your command you could try to give it a zero-length extension like so:
find . -exec sed -f sed.s -i '' {} \;

sed to exclude directories

I try to replace many files at once with sed using * as filename. However it tries to process directories too, and gives error and terminates. Is there a simple way to overcome this?
I'm not sure exactly how you're using sed here but the normal way to process only regular files in UNIX is with the find command, something like:
find . -type f -exec sed 's/Hello/Goodbye/g' {} ';'
The type restricts you to regular files, not directories or FIFOs or any other sort of filesystem magic.
If you run man find on your system, you will see a plethora of other options you can use.
To springboard on paxdiablo's answer, I cobbled this alias together, and added it to my bash aliases as 'recursive sed': rsed :
rsed() {
[[ -z $2 ]] && echo "usage: ${FUNCNAME[0]} oldtext newtext" && return
command find . -type f -exec sed -i "s/${1}/${2}/g" {} \;
}
Result:
> cat test/file
Hello how are you?
> rsed "Hello how are you?" "Fine thanks"
> cat test/file
Fine thanks