Cd to another directory to view a log file

Hi guys

Today I have been working on a script to execute to view entries within a log file.

I have successfully got the command I want to execute within the script itself. I want to view the last 5 entries within a log file and see just the last numbers. The file name would change depending on the date.

sort -rn $(ls -c localhost_access_log.*.txt | head -n 1) | sed -r '/HTTP\/1\.1" [0-9]+ [0-9]+ [0-9]$/d' | head -n 5 | grep POST | sed -e 's|^.*\s\(.*\)$|\1|'

Returns what I expect to see

2347
2433
2374
2328
2287

However I want to execute this within a shell script and the file is located within a different location to the log file.

I tried to setup an alias within the shell script but that hasn't worked so I am not 100% sure how to do this.

logfile=`cd '/opt/product/apachetomcat/8080/8.5.5_8080/apache-tomcat-8.5.5/logs'`

$logfile

last_install=`sort -rn $(ls -c localhost_access_log.*.txt | head -n 1) | sed -r '/HTTP\/1\.1" [0-9]+ [0-9]+ [0-9]$/d' | head -n 5 | grep POST | sed -e 's|^.*\s\(.*\)$|\1|'`

echo $last_install

exit 0

Any help would be much appreciated.

The log file location: /opt/product/apachetomcat/8080/8.5.5_8080/apache-tomcat-8.5.5/logs

Thanks in advance

Hi try:

logdir=/opt/product/apachetomcat/8080/8.5.5_8080/apache-tomcat-8.5.5/logs
cd "$logdir"
1 Like

Fantastic!

What was I doing wrong?

logdir='/opt/product/apachetomcat/8080/8.5.5_8080/apache-tomcat-8.5.5/logs'
cd "$logdir"

last_install=`sort -rn $(ls -c localhost_access_log.*.txt | head -n 1) | sed -r '/HTTP\/1\.1" [0-9]+ [0-9]+ [0-9]$/d' | head -n 1 | grep POST | sed -e 's|^.*\s\(.*\)$|\1|'`

echo $last_install

2308

Your line:

logfile=`cd '/opt/product/apachetomcat/8080/8.5.5_8080/apache-tomcat-8.5.5/logs'`

was nonsensical, as `` captures the output of a command and the cd command outputs nothing. So you were effectively doing logfile=''

1 Like

I am not sure but probably the various nested subshells are at fault. As Corona688 mentioned. I only saw your second version and did not realise in your first posting the "cd" was within the assignment. So let us go over your code:

logdir='/opt/product/apachetomcat/8080/8.5.5_8080/apache-tomcat-8.5.5/logs'
cd "$logdir"

last_install=`sort -rn $(ls -c localhost_access_log.*.txt | head -n 1) | sed -r '/HTTP\/1\.1" [0-9]+ [0-9]+ [0-9]$/d' | head -n 1 | grep POST | sed -e 's|^.*\s\(.*\)$|\1|'`

echo $last_install

First: you should NOT use the cd -command in a script. Never! Rather than

cd /some/where
command file

do it like this:

command /some/where/file

or, better yet (especially if you need the path several times, not once), like this:

mylocation="/some/where"
command1 "${mylocation}/file
command2 "${mylocation}/otherfile

Next: the various pipelines. Always be aware that calling a program takes time: to load the bnary, then to set up and start the sub-process, then to process the data and then remove the ended subprocess. Usually processing the data is the smallest part of this. Avoid these subproccesses.

Let us have a look:

last_install=`sort -rn $(ls -c localhost_access_log.*.txt | head -n 1) | sed -r '/HTTP\/1\.1" [0-9]+ [0-9]+ [0-9]$/d' | head -n 1 | grep POST | sed -e 's|^.*\s\(.*\)$|\1|'

this:

sed -r '/HTTP\/1\.1" [0-9]+ [0-9]+ [0-9]$/d' | head -n 1 | grep POST | sed -e 's|^.*\s\(.*\)$|\1|'

will do what? First, it deletes some lines with HTTP... in them, then takes the first remaining one, the filters out all lines with POST in them (there is only one line at that time) and then trims this line (if any). All of this can be done in a single invocation of sed:

sed -n '/HTTP\/1\.1" \([0-9][0-9]* \)\{2\}[0-9]$/ !{p;q}'

This is equivalent to your first sed-invocation plus the pipeline to head : it waits for the first line NOT containing "HTTP...", prints it and quits. All other lines are silently dropped because of the "-n". That means, only one line will be printed. I also removed the extended regexps. Only GNU-sed understands them since they are not POSIX and it is good practice to write scripts as portable as possible. Now the rest. I use another rule for lines containing "POST", which trims them and then prints them out. Regardless of something being printed or not, sed quits after this, so either a line with POST is printed or nothing:

sed -n '/HTTP\/1\.1" \([0-9][0-9]* \)\{2\}[0-9]$/ !{
                         /POST/ s/^.*\s//p
                         q;
       }'

Now for the rest of the command:

last_install=`sort -rn $(ls -c localhost_access_log.*.txt | head -n 1)....

Do you really want to access the file created last or could it be the file last modified? Maybe it won't matter because logfiles are usually created, written to, then the next one is created, etc. The sorting for modification time and the one for creation time would produce the same results in this case. In any way you should NOT use backticks any more. You used "$(...)" within, why not use them outside too?

last_install=$( sort -rn $(ls -c localhost_access_log.*.txt | head -n 1)....

And, finally, make your code better readable. Lines are free of charge, so you don't have to press everything into one line:

last_install=$( sort -rn $( ls -c "$logdir"/localhost_access_log.*.txt |\
                            head -n 1 \
                          ) |\
                sed -n '/HTTP\/1\.1" \([0-9][0-9]* \)\{2\}[0-9]$/ !{
                          /POST/ s/^.*\s//p
                          q;
                        }' \
              )

It might be only me, but i find this easier to comprehend what belongs to where. Perhaps even better:

lastlogfile=$( ls -c "$logdir"/localhost_access_log.*.txt | head -n 1 )
last_install=$( sort -rn "$lastlogfile" |\
                sed -n '/HTTP\/1\.1" \([0-9][0-9]* \)\{2\}[0-9]$/ !{
                          /POST/ s/^.*\s//p
                          q;
                       }' \
              )

I hope this helps.

bakunin

1 Like

Requirement no longer needed. Will close

Thanks