3

Based on this answer, I want to perform an operation on all the files in a directory and its subdirectories.

The following command works a single file, and also works when used on multiple files in a loop.

for i in *.html; \ do sed -i '/<head>/a <link rel="stylesheet" href="/home/jian/postgres/doc/src/sgml/html/stylesheet.css">\' $i; \ done 

But the following command will not work.

find . -type d -exec \ for i in *.html; \ do sed -i '/<head>/a <link rel="stylesheet" href="/home/jian/postgres/doc/src/sgml/html/stylesheet.css">\' $i; \ done \ \; 

It gives the following error:

bash: syntax error near unexpected token `do' bash: syntax error near unexpected token `done' ;: command not found 

I found a related post here.

3
  • 2
    Why are you running find . -type d -exec if you want to make an operation on html files? Why not find . -type f -name '*.html' and then exec the sed command directly on those files? Commented Nov 8, 2022 at 18:07
  • @aviro can you give a full answer.... Commented Nov 8, 2022 at 18:19
  • FYI, that first for loop of yours has an arbitrary command execution vulnerability as you forgot the -- (need with GNU find at least, the one that supports -i and can run commands) and the quotes around $i. Commented Nov 9, 2022 at 12:10

1 Answer 1

4

Calling sed from find for all regular files with names matching *.html in the current directory or below:

find . -name '*.html' -type f -exec sed -i '...expression...' {} + 

Assuming you correctly insert your sed expression in the code above, this will call sed with batches pathnames of found files, ensuring that sed is invoked as few times as possible.

Alternatively,

shopt -s globstar dotglob failglob sed -i '...expression...' ./**/*.html 

This enables the ** pattern which works like * but matches across / in pathnames ("recursively"). It also allows patterns to match hidden names (like find would also do), and tells the shell to fail with an error if no names matches a pattern.

The difference here is that

  1. The filetype of matching files is not tested (the pattern may match directories etc.)
  2. If the pattern matches many thousands of names, the command will fail to execute with a "Argument list too long" error.
2
  • sed -i '/<head>/a <link rel="stylesheet" href="/home/jian/postgres/doc/src/sgml/html/stylesheet.css">\' ./**/*.html seems not work. says: sed: can't read ./**/*.html: No such file or directory Commented Nov 9, 2022 at 4:11
  • 1
    @jian I believe you forgot to also run the shopt command that was part of that code. It was not merely decorative :-) Commented Nov 9, 2022 at 6:04

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.