8

Is it any way to find all files like *.js and insert some specific line at the beginning of the file? looking for something like:

find . -name '*.js' -exec sh -c '[insert this 'string'] "${0%.js}"' {} \;

codeforester
  • 28,846
  • 11
  • 78
  • 104
Sarkis Arutiunian
  • 1,135
  • 13
  • 30

2 Answers2

12

Here's a way to add a line to the beginning of a file:

sed -i '1s/^/line_to_be_added\n/' file

Then, you could use the code above with find to achieve your ultimate goal:

find . -type f -name '*.js' -exec sed -i '1s/^/line_to_be_added\n/' {} \;

Note: this answer was tested and works with GNU sed.

Edit: the code above would not work properly on a .js file that is empty, as the sed command above does not work as expected on empty files. A workaround to that would be to test if the file is empty, and if it is, add the desired line via echo, otherwise add the desired line via sed. This all can be done in a (long) one-liner, as follows:

find . -type f -name '*.js' -exec bash -c 'if [ ! -s "{}" ]; then echo "line_to_be_added" >> {}; else sed -i "1s/^/line_to_be_added\n/" {}; fi' \;

Edit 2: As user Sarkis Arutiunian pointed out, we need to add '' before the expression and \'$' before \n to make this work properly in MacOS sed. Here an example

sed -i '' '1s/^/line_to_be_added\'$'\n/' filename.js

Edit 3: This also works, and editors will know how to syntax highlight it:

sed -i '' $'1s/^/line_to_be_added\\\n/' filename.js
Iulian Onofrei
  • 7,489
  • 8
  • 59
  • 96
Jamil Said
  • 1,825
  • 3
  • 12
  • 18
  • 3
    Thanks! But a couple more things, on OSX, you need to add `''` after `-i` like so: `sed -i '' '1s/^/line_to_be_added\n/' file` or it won't work, and `\n`, doesn't work, it just ignoring `\` and inserting symbol `n` – Sarkis Arutiunian May 15 '17 at 16:07
  • @Sarkis Arutiunian Thanks for the info. I don't have `OSX` installed, thus I can't test on that either. I believe that one has to use `\\\n` on `sed` `OSX` to make the `newline` thing to work, right? How did you get the `sed` `newline` working on `OSX`? – Jamil Said May 15 '17 at 18:58
  • 3
    no, this one `\'$'\n/` so full command will be `sed -i '' '1s/^/line_to_be_added\'$'\n/' file` – Sarkis Arutiunian May 15 '17 at 19:06
  • 1
    @Sarkis Arutiunian Great, thanks for posting this, I learned a new thing and this will help others as well. – Jamil Said May 15 '17 at 19:08
  • @JamilSaid: It will help others even more if you make this information _part of your answer_ - people tend to ignore comments, especially in lengthy exchanges. Also note that `sed` has a _dedicated function_ for inserting text: `i`( similarly, there's `a` for _appending_ text). Portable use is again tricky, however: `sed '1i/line_to_be_added/' file` would work with _GNU_ `sed`, but a _portable_ command (that would also work on macOS, for instance) would require `i` to be followed by a `\` and the insertion string to be followed by another ``. – mklement0 May 15 '17 at 23:16
5

Portability: Use Sed's Hold Space

If you want a solution that works portably with both GNU and BSD sed, use the following to prepend text to the first line, and then pass the rest through unchanged:

sed '1 { x; s/^.*/foo/; G; }' example.txt

Assuming a corpus of:

bar
baz

this will print:

foo
bar
baz

You can save the transformation in a script, and then use find or xargs and the sed -i flag for in-place edits once you're sure everything is working the way you expect.

Caveat

Using sed has one major limitation: if the file is empty, it won't work as you might expect. That's not something that seems likely from your original question, but if that's a possibility then you need to use something like cat <(echo foo) example.txt | sponge example.txt to edit the file in-place, or use temporary files and move them after concatenating them.

NB: Sponge is non-standard. It can be found in the moreutils package.

Todd A. Jacobs
  • 71,673
  • 14
  • 128
  • 179
  • There is no need for the arcane `x` and `G` Sed functions, because there's a dedicated function for inserting text: `i`. Yes, you need `\ ` followed by an _actual_ newline before and after the text to insert for portable use, but that's a small price to pay, and, in `bash`, `ksh`, `zsh`, you can use an ANSI C-quoted string if a single-line solution is a must. E.g., `sed $'1i\\\ninsert me\n'` will do. – mklement0 May 15 '17 at 23:05
  • 2
    Speaking of arcane (on a meta note, since it appears to be a habit of yours): Please don't use the word "corpus" when much more common words such as "input" or "text" will do. Aside from being needlessly arcane, using "corpus" the way you do is [inconsistent with common usage](https://www.ahdictionary.com/word/search.html?q=corpus). – mklement0 May 15 '17 at 23:05
  • @mklement0 if they're so arcane, why are these options still included in recent distributions of `sed` then? Why are they not deprecated? Your solution doesn't allow for shell variables to be used directly in the search or replacement strings, but you _can_ with the provided answer (and changing the op string to double quotes). So there's another "price" to pay if you wanted to do that with your suggestion, and if you do, you're likely to have a solution that actually is more messy if not more "arcane" looking than what was originally provided. – Jon May 25 '21 at 22:00
  • Now that you've edited the vitriol out of your comment, @Jon, let me reply in earnest: the quality of being arcane is unrelated to deprecation; the core meaning of arcane is "understood by few", which relates to two factors, the first of which usually begets the second: conceptual complexity impeding comprehension, and infrequent use in practice. I think both factors apply here, but you do have a point about string interpolation, which ANSI C-quoting doesn't support. However, you can simply use a _multi-line_ `"..."` string. – mklement0 May 25 '21 at 23:37
  • I see you use still haven't edited the the Wile E. Coyote out of yours. So if we're using multi-line string in function code that is indented for readability, we must make further sacrifices in order to preserve indentation on new lines for readability. On the suitability of the original solution, your conclusion is that these `sed` functions are either not used in practice (which I doubt you have comprehensive evidence for) or that it's too _conceptually complex_ to comprehend. I really don't think any factor applies, and your suggestions to others comes across as very presumptuous. – Jon May 28 '21 at 18:09