Your command is slightly wrong as <<<
is an input redirection (here-string) that is attached to find
, not to ed
.
To expand slightly on your command:
find . -type f -exec sh -c '
for pathname do
echo w | ed -s "$pathname"
done' sh {} +
This would only affect regular files in the current directory or anywhere below it, and would not try to edit directories and other filetypes with ed
. Note that binary files are also regular files, so we must assume that you only run this in directories containing text files (as to not damage compiled executables, image files, etc.)
For batches of regular files, this would call a short in-line shell script. The script would loop over the pathnames given to it by find
and would open each in ed
, only to immediately save the file. This adds the newline to files that does not already end with a newline character.
To get a hint about what files are actually modified by this, print out the pathname before calling ed
. This would output all found pathnames, but the list would be interspersed by "Newline added" messages after some of them.
find . -type f -exec sh -c '
for pathname do
printf "%s\n" "$pathname"
echo w | ed -s "$pathname"
done' sh {} +
To detect which files were actually modified by this, you could write to a temporary file, compare that with the original file, and replace the original with the temporary file if there is a difference.
find . -type f -exec sh -c '
tmpfile=$(mktemp); trap "rm -f \"$tmpfile\"" EXIT
for pathname do
printf "w %s\n" "$tmpfile" | ed -s "$pathname" 2>/dev/null
if ! cmp -s "$tmpfile" "$pathname"; then
printf "Fixed %s\n" "$pathname"
mv "$tmpfile" "$pathname"
fi
done' sh {} +
This has the added benefit that you won't be updating timestamps on files other than the ones that you actually modify.
This also suppresses the "Newline added" message from ed
and instead outputs a custom message whenever a file has actually been modified.
See also:
ed
, which is loading and rewriting the whole file, making a copy of it. Instead, just check if the file ends in a newline withtail -c
, and if not, append a newline:find . -type f -exec sh -c 'for a do [ "$(tail -c -1 "$a")" ] && { echo >>"$a" ; echo "+++ $a"; }; done' sh {} +
– Mar 19 '20 at 22:15isn't adding it back
– Because<<< w
affectsfind
. Everyed
uses the same stdin asfind
. The very firsted
consumesw\n
and then the stream is empty for any othered
. – Kamil Maciorowski Mar 19 '20 at 22:26ed -s filename <<< w
from somewhere on this website and I assumed that I could just place it into afind
command. – Aaron Franke Mar 19 '20 at 22:27<
but the issue is the same. – Kamil Maciorowski Mar 19 '20 at 22:30