1

I have some files in a directory. And I want to add some lines at top and end of file using awk.

Example: My awk command:

awk 'BEGIN { print "line1\nline2" } { print $0 } END { print "line3\nline4" }' file |tee file

By using above command I can add line1 & line2 at the top & line3, line4 at the end of file

Now I want to do same action for all files that are exist in current directory.

If I use :

awk 'BEGIN { print "line1\nline2" } { print $0 } END { print "line3\nline4" }' *

Then I get output on terminal screen but I can't redirect to (or overwrite) all files.

So, I tried following (To find + awk):

find -type f -exec awk 'BEGIN { print "line1\nline2" } { print $0 } END { print "line3\nline4" }' '{}' \;

By using above command I can print output on screen and hence to overwrite files,

I've tried following (To find + awk + overwrite with tee), but it getting error:

$ find -type f -exec awk 'BEGIN { print "line1\nline2" } { print $0 } END { print "line3\nline4" }' '{}' | tee '{}' \;
find: missing argument to `-exec'

Hence, How can I use awk to overwrite (i.e: with |tee or something else) for all files in current directory by command?

  • Like sed -i, GNU awk has an in-place editing plugin: gawk -i inplace. – muru Jan 20 '15 at 14:34
  • 2
    @muru, -i inplace doesn't work for BEGIN and END statements though (works for BEGINFILE, but not ENDFILE) – Stéphane Chazelas Jan 20 '15 at 14:38
  • 3
    Decision1: Use sed instead of awk (sed -is -e '1 i\...' -e '$ a\...' *). Decision2 Use loop for for each file in directory (for file in *; do awk '...' "$file" | tee "$file" ; done). – Costas Jan 20 '15 at 14:40
6

With GNU awk 4.1 or above:

find . -type f -exec awk '
   @load "inplace"
   BEGINFILE {
     inplace_begin(FILENAME, "")
     print "line1\nline2"
   }
   {print}
   ENDFILE {
     print "line3\nline4"
     inplace_end(FILENAME, "")
   }' {} +
  • What is meant by GNU awk : awk or gawk ? – Pandya Jan 20 '15 at 16:37
  • Find: Only one instance of {} is supported with -exec ... + – Pandya Jan 20 '15 at 16:39
  • 1
    @Pandya, on GNU systems, awk will generally be the GNU implementation. On non-GNU systems, GNU awk may be available as gawk. – Stéphane Chazelas Jan 20 '15 at 17:00
  • @Pandya, I can see only one instance of {} in the code I supplied. Are you sure you copied it properly? – Stéphane Chazelas Jan 20 '15 at 17:01
  • I am using Trisquel GNU/Linux and only GNU awk version 4.0 is available for Belenos (latest) release. So I've to download GNU awk 4.1 from Ubuntu's utopic(14.10) branch! – Pandya Jan 21 '15 at 13:41
2

Decision1: Use GNU sed instead of awk

sed -i -e '1 i\line1\nline2' -e '$ a\line3\nline4' ./* 

Decision2: Use loop for for each file in directory

for file in ./*
do
  awk '
       BEGIN { print "line1\nline2" }
       { print $0 }
       END { print "line3\nline4" }
      ' "$file" > "$file".tmp &&
    mv -f "$file".tmp "$file"
done
  • 1
    Note that the sed one won't work for empty files. About the second one, using a fixed file name in /tmp is dangerous and means mv will do a file copy if /tmp is a different filesystem. Also note that permissions and ownership won't be preserved and that would break symlinks. – Stéphane Chazelas Jan 20 '15 at 17:18
  • As Stéphane Chazelas's answer uses only awk and resulting best one, I accepted it. Anyway +1 – Pandya Jan 21 '15 at 13:34

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.