23

I want to remove the first line of multiple text files and replace it with another line. Is there a way to do this using the terminal?

I know how to use vim, is there a way to automate it with it? I want to avoid doing it manually (as in editing each file individually).

If possible I'd like to avoid installing new libraries (especially for something like that which i consider very simple - but I could be wrong).

Thanks in advance!

7 Answers 7

26

You can use sed :

sed -i.bak '1s/^.*$/new line/' *.txt

This will replace the first line of all .txt files in the current directory with the text new line, change it to meet your need.

Also the original files will be backed up with .bak extension, if you don't want that just use :

sed -i '1s/^.*$/new line/' *.txt
2
  • Thank you! sed is actually what i was looking for!
    – TomTsagk
    Aug 1, 2015 at 23:08
  • @TomTsagk Glad i could help :)
    – heemayl
    Aug 1, 2015 at 23:08
15

Well, using vim itself:

vim -Nesc 'bufdo call setline(1,"This is the replacement.") | wq' file1 file2 ...

What this does:

  • setline (n, text), well, is a function that sets line n to text.
  • call is needed to call functions.
  • bufdo is used to repeat a command across buffers (without a range, it acts on all buffers).
  • wq saves and quits the buffer. We need to do this before moving on to the next buffer, so this command is chained to the call command using |.
  • -c cmd runs cmd is a command-mode command after loading the first buffer.
  • Nes turns on no-compatible, silent, ex-mode, which is better for non-interactive processing.

Benefits:

  • The setline text content can be anything - an & in a sed replacement text can have unintended effects.
3
  • sed seems much easier to use, but it's really awesome that vim can do the same! Thanks a lot for your answer!
    – TomTsagk
    Aug 1, 2015 at 23:23
  • @TomTsagk well, I just wanted to illustrate how you could act across multiple files (bufdo). Consider you having the files already open and ... And to show an alternate to 1s/foo/bar/.
    – muru
    Aug 2, 2015 at 0:33
  • Awesoming!!! <3_<3
    – Campa
    Aug 5, 2015 at 6:50
4

A few other options:

  • awk (needs a relatively new version of GNU awk)

    $ awk -i inplace -vline="new line" '(FNR==1){print line; next}1;' *.txt
    
  • Perl/shell

    $ for f in *txt; do
        perl -i -lne '$.==1 ? print "new line" : print' "$f"
      done
    
  • Shell/coreutils

    $ for f in *txt; do 
        ( echo "new line"; tail -n+2 "$f" ) > foo && mv foo "$f"; 
      done
    
2

This script will do as you requested, placing the changed files in a new directory without actually changing the originals.

d=/tmp/cooked
mkdir $d
for f in *  #will match all files in current directory; adjust as desired
do
  echo "This is the new 1st line" > /${d}/${f}
  sed 1d ${f} >> /${d}/${f}
done
1
  • I was slow answering (tested my code)...and I like heemayl's solution a lot better! Aug 1, 2015 at 23:07
1

Using gawk

gawk -i inplace 'FNR==1 {$_="your_replacement"}; {print}' *.txt

Example

% cat foo.txt 
1
2
3
4

% cat bar.txt 
1
2
3
4

% gawk -i inplace 'FNR==1 {$_="your_replacement"}; {print}' *.txt

% cat foo.txt                                                    
your_replacement
2
3
4

% cat bar.txt                                                    
your_replacement
2
3
4
0

The tail and cat commands would do this easily:

tail -n +1 $file > tmpfile
cat newfirstline tmpfile >$file

Wrap those in a suitable loop and perhaps use a proper and righteous temporary file instead of a hard-coded temporary file name. I believe bash and other shells have a syntax for creating temporary files.

The -n option of tail has two interpretations depending on whether the argument has a plus sign. If it has a plus sign then it means to show the tail of the file starting at the given line number. Otherwise the number is the number of lines, including the last line, that tail is supposed to output.

0

rpl is so much better than sed.

Oh my goodness, finally a solution that's straightforward:

rpl "myFlag=True" "myFlag=False" *.cfg

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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