Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am new in awk and I do not know if it is possible to write an awk script that does this:

I have hundred of data files that I have to sort. For each one I use the following one-liner:

awk 'ORS=NR%3?" ":"\n" ' file1.tex >  file1_sorted.tex
awk 'ORS=NR%3?" ":"\n" ' file2.tex >  file2_sorted.tex
...

and I get the output I need. However I would like to have an script to automate this action, taking each file, applying the action and writing the corresponding sorted file.

I would appreciate your help!

share|improve this question

2 Answers 2

up vote 4 down vote accepted

If you modify the awk code, can be solved by a single awk process and no shell loop:

awk 'FNR==1{if(o)close(o);o=FILENAME;sub(/\.tex/,"_sorted.tex",o)}{ORS=FNR%3?" ":"\n";print>o}' *.tex

Not a beauty, just insignificantly faster.

Explanations as requested in comment.

FNR (file number or record) is similar to NR (number or record), but while NR is a continuous sequence number of all input records, FNR is reset to 1 when processing of a new input file is started.

A gawk 4.0 only alternative for the FNR==1 is the BEGINFILE special pattern.

awk '
FNR==1{   # first record of an input file?
  if(o)close(o);   # was previous output file? close it
  o=FILENAME;sub(/\.tex/,"_sorted.tex",o)   # new output file name
}
{
  ORS=FNR%3?" ":"\n";   # set ORS based on FNR (not NR as in the original code)
  print>o   # print to the current output file
}
' *.tex
share|improve this answer
    
Thanks @manatwork! That was awesome. Unlike the last answer, I do not get exactly how does this one-liner work, but it did. If you have time, I would thank you if you could explain to me what does FNR==1 do. =) –  Nacu Feb 20 '12 at 18:50

You can apply the files in a for loop:

for file in *.tex;
do
    awk 'ORS=NR%3?" ":"\n"' "$file" > "$(basename "$file")_sorted.tex"
done

Or on one line:

for file in *.tex; do awk 'ORS=NR%3?" ":"\n"' $file > "$(basename "$file" .tex)_sorted.tex"; done

Since you don't specify which shell, go with the more standard basename instead using the shell specific syntax ${file%%.tex}.

share|improve this answer
1  
That “shell-specific syntax” is in POSIX and is available on practically every unix system that's still under warranty, and many that aren't. –  Gilles Feb 19 '12 at 23:55
    
Thanks @Arcege!, I use emacs as shell. Although your suggestion is pretty understandable, I do not know how to use it. As far as I understand and I have been practiced, one writes an .awk script that you run before the file or folder you want to apply it to. Am I right? I did that, however this seems another kind of script that I do not know how to use. –  Nacu Feb 20 '12 at 18:41
    
You can run a shell inside emacs (<kbd>M-x</kbd>shell) and run the commands above inside that at the prompt. Or open a terminal and run the command there. There are two ways to specify (awk, shell, etc) scripts: either on the command-line or in a file. Your awk command in the posting uses the command-line form; my "one line" command is also a command-line form. –  Arcege Feb 20 '12 at 19:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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