Print n lines from top and n lines from bottom of all files with .log extenstion

Oracle Linux 6.4

In a directory I have more than 300 files with the extension .log

I want the first 5 and last 5 lines of these .log files to be printed on screen with each file's name.

Expected output :

Printing first 5 and last 5 lines of FX_WT_Feb8_2014.log

 !! Authentication dialogue with 10.79.60.158 failed
   R:  !! Failed to pull policy from policy server
   R:  !! Did not start the scheduler
   There is no readable input file at promises.cf
    !!! System error for stat: "No such file or directory"
   
 
 !! Authentication dialogue with 10.79.60.158 failed
    R:  !! Failed to pull policy from policy server
    R:  !! Did not start the scheduler
    cf-agent was not able to get confirmation of promises from cf-promises, so going to failsafe
There is no readable input file at promises.cf

Try the below code

#!/bin/ksh
ls *.log > list_of_log_files
for file in `cat list_of_log_files`
do
echo "$file"
head -5 $file
tail -5 $file
done
echo "Files are completed"

Please update first line (the shell type) in your script. you can find the script type by
executing echo $SHELL

Hope it helps

1 Like

Note: Instead of

ls *.log > list_of_log_files
for file in `cat list_of_log_files`

A better option is:

for file in *.log
2 Likes

Here are a couple of ways to do it that match the requested output format a little closer:

#!/bin/ksh
n=0
for file in *.log
do      [ $((n++)) -gt 0 ] && echo
        printf "Printing first 5 and last 5 lines of %s.\n\n" "$file"
        head -n 5 "$file"
        printf "\n\n\n"
        tail -n 5 "$file"
done

If this fails because the expansion of *.log exceeds ARG_MAX limitations, you can use this instead:

n=0
ls | while IFS='' read -r file
do      case "$file" in
        (*.log) [ $((n++)) -gt 0 ] && echo
                printf "Printing first 5 and last 5 lines of %s.\n\n" "$file"
                head -n 5 "$file"
                printf "\n\n\n"
                tail -n 5 "$file";;
        esac
done

If you don't want an empty line between reports for separate files, comment out or remove the code shown in red.

Although written for ksh, both of these will also work with bash or any other shell that supports standard POSIX shell syntax.

1 Like

IMO, the expansion of *.log cannot exceed ARG_MAX limitations since for .. in is shell syntax, so there is no new process to which arguments need to be passed..

3 Likes

Yes, you are absolutely correct.

I was looking at ls *.log in kung_fu_panda's proposal (which can exceed ARG_MAX limitations). I should have gotten some sleep before I posted my response.

Thanks,
Don

Out of curiosity...

[C|W]ould either find *.log > result;while read line; do ... done<result ) or for found in $(find *log);do ... reach ARG_MAX limitations?
Mainly asking, would "find" be a better 'tool' than "ls"?

EDIT:
Obviously it would require ls -r to be compareable with find

Yes both of them could reach ARG_MAX limitations. find . -name '*.log' on the other hand would not.

--
for var in $( ... ) is not a good method by the way with the default IFS, since $( ... ) (command substitution) is subject to field splitting, so file names with spaces would be broken up..

1 Like