28

I have a directory full of text files. My goal is to append text to the beginning and end of all of them. The text that goes at the beginning and end is the same for each file.

Based on code I got from the web, this is the code for appending to the beginning of the file:

echo -e 'var language = {\n$(cat $BASEDIR/Translations/Javascript/*.txt)' > $BASEDIR/Translations/Javascript/*.txt

This is the code for appending to the end of the file. The goal is to add the text }; at the end of each file:

echo "};" >> $BASEDIR/Translations/Javascript/*.txt

The examples I drew from were for acting on individual files. I thought I'd try acting on multiple files using the wildcard, *.txt.

I might be making other mistakes as well. In any case, how do I append text to the beginning and end of multiple files?

9 Answers 9

34

To prepend text to a file you can use (with the GNU implementation of sed):

sed -i '1i some string' file

Appending text is as simple as

echo 'Some other string' >> file

The last thing to do is to put that into a loop which iterates over all the files you intend to edit:

for file in *.txt; do
  sed -i '1i Some string' "$file" &&
  echo 'Some other string' >> "$file"
done
1
  • Might be worth mentioning (I missed this detail) that the 1i at the beginning of the string passed to sed is very important here! It's an instruction to "insert before line 1"
    – Nick F
    Apr 6 at 17:12
9

You can use GNU sed

Like already illustrated, you can insert lines of text right before and after matching lines of a file with sed, using the i and a command respectively. What hasn't been shown is that you can do it with a one-liner and for multiple files at once.

The following will insert a line before the first 1i and after the last line $a. The insertions will be executed for all files matching the glob *.txt.

sed -i -e '1ivar language = {' -e '$a};' -- *.txt

Both i and a do not only work with line numbers, but also on every line that matches a given pattern. This would insert a comment whenever a line contains var y = 2;:

sed -i -- '/var y = 2;/i//initialize variable y' *.js
6

Fully POSIX compliant command, using ex:

for f in *.txt; do printf '%s\n' 0a 'var language = {' . '$a' '};' . x | ex "$f"; done

If you run the printf portion of the command by itself, you will see the exact editing commands that it is passing to ex:

0a
var language = {
.
$a
};
.
x

0a means "Append text after line 0" (in other words, before the first line). The next line is the literal text to "append" after line 0. The period (.) on a line by itself ends the text to be appended.

$a means to append text after the last line of the file.

x means to save the changes and exit.

2

Here's a way to do it in Perl:

for f in ./*txt; do
  perl -lpe 'BEGIN{print "First string"}END{print "Last string"}' "$f" > foo && 
  mv foo "$f";
done
2
  • @StéphaneChazelas adding -i instead of this file substitution does not work, it just prints to stdout. May 31, 2016 at 20:23
  • @OlehPrypin, indeed your right. Comment deleted. Jun 1, 2016 at 6:31
2

Also has the right to be (with results in .out files):

find . -name '*.txt' -exec sh -c '(echo HEAD;cat {};echo FOOT) > {}.out' \;

Another, more elaborated variant - source files replaced with result:

find . -name '*.txt' -exec sh -c '(echo HEAD;cat {};echo FOOT) > {}.tmp && mv {}.tmp {}' \; -print
1

Try using ex:

ex -s +'bufdo!1s/^/HEAD/|$s/$/TAIL/' -cxa *.foo

where commands are:

  • bufdo! executes below commands for each opened buffer/file (note: it's not POSIX)
  • 1s/^/HEAD/ - inserts HEAD text into the first line at the beginning of the line
  • $s/$/TAIL/ - appends TAIL text on the last line at the end of the line

and arguments are:

  • -s - silent/quick mode
  • -cxa - save all opened buffers/files and quit
  • *.foo - all files in the current directory (*) with foo extension, use **/*.foo for recursivity (after enabling globstar: shopt -s globstar)
2
1

With gnu awk, using the inplace extension and BEGINFILE/ENDFILE:

gawk -i inplace 'BEGINFILE{print "INSERT"};ENDFILE{print "APPEND"};1' ./*.txt
0

Perl one-liner to the rescue:

perl -i -pe'$_="FIRST LINE\n$_"if$.<2;$.=0,$_.="LAST LINE\n"if eof' *.txt
1
  • Perhaps explain the process of this (typically) terse program.
    – Walf
    Feb 2, 2022 at 7:02
0

A solution that makes use of the shell, and is considerably more readable than some other solutions is to use a basic loop and a temporary file:

for file in $BASEDIR/Translations/Javascript/*.txt; do
    echo 'var language = {' | cat - "$file" > /tmp/my-modified-file && \
        echo '};' >> /tmp/my-modified-file && \
        mv /tmp/my-modified-file "$file"
done

This can be modified to a while loop if you need to pipe filenames from programs like find or grep -l:

find /path/ -name '*someword*.myext' | while read -r file; do
    ...
done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .