I have a list of file names and line numbers in the following format:

./foo.txt:1:(more characters)
./foo.txt:3:(more characters)
./bar.txt:10:(more characters)

The list could be from a file or it could be output by a process (for example, grep -n).

I want to append some fixed text to each of the referenced lines, modifying the files in place.

For example, if the file foo.txt contains the following text:


I want it to be modified to contain:

Three TODO

Similarly, " TODO" should be appended to line 10 of bar.txt.

How can I do this?

  • 1
    Passing file names like this is tricky. If the file name contains : or new line, it will fail.
    – pLumo
    Apr 23 '19 at 13:04
  • Well when text is coming from a stream than you could use sed as follows: ... | sed 's/\(.*\)/\1 foo/' or ... | sed 's/.*/& foo/' Apr 23 '19 at 13:15
  • @ValentinBajrami it seems to me that the intention is to edit the referenced files, not the stream/input itself.
    – Jeff Schaller
    Apr 23 '19 at 13:27
  • @ValentinBajrami: JeffSchaller is correct. I updated the question to make this clearer, it now specifically states that "the referenced lines" are to be modified.
    – Martin
    Apr 23 '19 at 13:30

One option: use ed!

while IFS=: read -r filename linenumber junk
  ed -s "$filename" <<< "$linenumber"$'s/$/ TODO/\nw\nq'
done < input
  • Does this have an advantage over using sed as per @RoVo's answer? Seems like the solutions are pretty similar, but the sed invocation looks a bit more tidy to me.
    – Martin
    Apr 23 '19 at 13:47
  • I wanted to put together a sed solution that batched all the edits for a single file together, to save some I/O. For example: sed -i -e 1s/$/TODO -e 3s/$/TODO ./foo.txt ... but didn't. Implementation left as an exercise for another Answerer :)
    – Jeff Schaller
    Apr 23 '19 at 14:02

Assuming your file names do contain neither : nor newline:

echo "$list_of_file_names" | while IFS=: read -r file line text; do
  sed -i "$line"'s/$/ TODO/' "$file"

Note: I think this is a pretty bad idea as

  • it is inefficient (runs sed for each line).
  • it will break on file names including : or \n.

Better use sed or awk for finding matching files+lines and appending text to them.

  • Good caveat about the : or newline in the file name.
    – Martin
    Apr 24 '19 at 9:01
  • Using sed or awk for finding and updating also seems like a good idea, provided it is feasible - which may not be the case, depending on how the list is generated. In fact, in the application that motivated the question, the list comes from an (improvised) code analysis script that is built around a grep invocation, but performs some additional processing.
    – Martin
    Apr 24 '19 at 9:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.