Cat last line linux

How to get the last line of a file using cat command

I am writing a shell script in OSX(unix) environment. I have a file called test.properties with the following content: cat test.properties gets the following output:

//This file is intended for //blah blah purposes 123 

It’s probable because this is one of the «How do I use X to do Y?» questions where X does not do Y. Such questions are not as useful as «How do I do Y?» or «What does X do?».

// , Those of us who think X will do Y, when, in reality, Z does Y (ahem) do benefit from such questions, in spite of their dubious pedagogy.

2 Answers 2

Don’t use cat . tail was meant for this usecase exactly:

Don’t have enough reputation to comment Mureinik’s post to answer your last question, but if you want to display a part of a file between known lines, you can try sed -n ‘,p .

If you don’t know the lines, mix tail and sed : For your file :

tail -r test.properties | sed -n '2p' 

Hot Network Questions

Subscribe to RSS

To subscribe to this RSS feed, copy and paste this URL into your RSS reader.

Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.14.43533

By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.

Источник

How to read first and last line from cat output?

When reading from stdin if would look like this (for example ps -ef ):

ps -ef | sed -e 1b -e '$!d' UID PID PPID C STIME TTY TIME CMD root 1931 1837 0 20:05 pts/0 00:00:00 sed -e 1b -e $!d 

head & tail Solution:

When data is coming from a command ( ps -ef ):

ps -ef 2>&1 | (head -n1 && tail -n1) UID PID PPID C STIME TTY TIME CMD root 2068 1837 0 20:13 pts/0 00:00:00 -bash 

awk Solution:

And also the piped example with ps -ef :

ps -ef | awk 'NR==1; END' UID PID PPID C STIME TTY TIME CMD root 1935 1837 0 20:07 pts/0 00:00:00 awk NR==1; END

Thank you! It’s the best answer because i cannot do (head -n1 file;tail -n1 file) i have very big command and pipe as last symbol. So | sed ‘1p;$!d’ shorter one.

Sorry for my English, if you don’t understand me — it’s my problem — tell me about it and i prepare better presentation for you.

@DavidConrad, to elaborate on what chaos said, -e 1b — on the first line, branch to the end of the sed script, at which point the implicit «print» happens. If the input is only one line long, sed ends. Otherwise, for all lines except the last, delete. On the last line, the implicit «print» happens again.

Читайте также:  Отличие линукса от бифидумбактерина

@mikeserv: 😉 check it when you get a chance. On a single line it efectively prevents doubling it on output, but on a multiple line work-case, it just preserves the last line. at least on GNU sed 4.2.2. Cheers.

sed -n ‘1p;$p’ file.txt will print 1st and last line of file.txt .

Note that if the input has only one line, it will be printed twice. You may prefer sed -e 1b -e ‘$!d’ if you don’t want that.

cb() < (($1-1>0)) && unset "ary[$1-1]"; > mapfile -t -C cb -c 1 ary < file 

After this, you'll have an array ary with first field (i.e., with index 0 ) being the first line of file , and its last field being the last line of file . The callback cb (optional if you want to slurp all lines in the array) unsets all the intermediate lines so as to not clutter memory. As a free by-product, you'll also have the number of lines in the file (as the last index of the array+1).

$ mapfile -t -C cb -c 1 ary < <(printf '%s\n' ) $ declare -p ary declare -a ary='([0]="a" [25]="z")' $ # With only one line $ mapfile -t -C cb -c 1 ary < <(printf '%s\n' "only one line") $ declare -p ary declare -a ary='([0]="only one line")' $ # With an empty file $ mapfile -t -C cb -c 1 ary < <(:) declare -a ary='()' 

Источник

How can I read first n and last n lines from a file?

How can I read the first n lines and the last n lines of a file? For n=2 , I read online that (head -n2 && tail -n2) would work, but it doesn't.

$ cat x 1 2 3 4 5 $ cat x | (head -n2 && tail -n2) 1 2 

Also, the link you sent is not helpful because I do not know the range really. I am looking for a simple solution for this

Interestingly, cat x | (head -n2 && tail -n2) doesn't work but (head -n2 && tail -n2) < x does. I'll have to meditate a bit on why that is.

What would the expected output be if the input file was 3 lines long? Would it be 1 2 3 or 1 2 2 3 or something else? What if it was only 2 lines long - would the output be 1 2 1 2 or 1 1 2 2 or 1 2 or something else?

I don't think the head && tail trick is reliable. head from GNU coreutils behaves differently for pipes and regular files (source: the source), reading blockwise in one case but not the other. Depending on implementation details like that seems like a bad idea -- it's not guaranteed that head will leave everything it doesn't print for tail to work with.

10 Answers 10

head -n2 file && tail -n2 file 

This isn't guaranteed to work even if your file is longer than 4 lines, if a single head buffer is so long enough that there aren't enough lines left in the file for tail to work.

Chances are you're going to want something like:

or if you need to specify a number and taking into account @Wintermute's astute observation that you don't need to buffer the whole file, something like this is what you really want:

I think the math is correct on that - hopefully you get the idea to use a rotating buffer indexed by the NR modded by the size of the buffer and adjusted to use indices in the range 1-n instead of 0-(n-1).

To help with comprehension of the modulus operator used in the indexing above, here is an example with intermediate print statements to show the logic as it executes:

$ cat tst.awk BEGIN < print "Populating array by index ((NR-1)%n)+1:" > < buf[((NR-1)%n)+1] = $0 printf "NR=%d, n=%d: ((NR-1 = %d) %%n = %d) +1 = %d ->buf[%d] = %s\n", NR, n, NR-1, (NR-1)%n, ((NR-1)%n)+1, ((NR-1)%n)+1, buf[((NR-1)%n)+1] > END < print "\nAccessing array by index ((NR+i-1)%n)+1:" for (i=1;i<=n;i++) < printf "NR=%d, i=%d, n=%d: (((NR+i = %d) - 1 = %d) %%n = %d) +1 = %d ->buf[%d] = %s\n", NR, i, n, NR+i, NR+i-1, (NR+i-1)%n, ((NR+i-1)%n)+1, ((NR+i-1)%n)+1, buf[((NR+i-1)%n)+1] > > $ $ awk -v n=3 -f tst.awk file Populating array by index ((NR-1)%n)+1: NR=1, n=3: ((NR-1 = 0) %n = 0) +1 = 1 -> buf[1] = 1 NR=2, n=3: ((NR-1 = 1) %n = 1) +1 = 2 -> buf[2] = 2 NR=3, n=3: ((NR-1 = 2) %n = 2) +1 = 3 -> buf[3] = 3 NR=4, n=3: ((NR-1 = 3) %n = 0) +1 = 1 -> buf[1] = 4 NR=5, n=3: ((NR-1 = 4) %n = 1) +1 = 2 -> buf[2] = 5 NR=6, n=3: ((NR-1 = 5) %n = 2) +1 = 3 -> buf[3] = 6 NR=7, n=3: ((NR-1 = 6) %n = 0) +1 = 1 -> buf[1] = 7 NR=8, n=3: ((NR-1 = 7) %n = 1) +1 = 2 -> buf[2] = 8 Accessing array by index ((NR+i-1)%n)+1: NR=8, i=1, n=3: (((NR+i = 9) - 1 = 8) %n = 2) +1 = 3 -> buf[3] = 6 NR=8, i=2, n=3: (((NR+i = 10) - 1 = 9) %n = 0) +1 = 1 -> buf[1] = 7 NR=8, i=3, n=3: (((NR+i = 11) - 1 = 10) %n = 1) +1 = 2 -> buf[2] = 8 

+1 since this works in a pipe. You might add a more elaborated version which takes files (streams) into account having less then 4 (head+tail) lines..

@EdMorton But it would still need to buffer the whole stream in memory.. (However I don't see a way without buffering if it should work in a pipe, except saving the stream into a temporary file)

I understand but the bug was just that I was setting ORS='\n' when I should have been setting OFS='\n' . Now that that's fixed there's no need to explicitly hard-code "\n" s between fields.

This might work for you (GNU sed):

This keeps a window of 2 (replace the 2's for n) lines and then prints the first 2 lines and at end of file prints the window i.e. the last 2 lines.

Here's a GNU sed one-liner that prints the first 10 and last 10 lines:

If you want to print a '--' separator between them:

If you're on a Mac and don't have GNU sed, you can't condense as much:

Explanation

gsed -ne' invoke sed without automatic printing pattern space

-e'1,9' print the first 9 lines

-e'10' print line 10 with an appended '--' separator

-e':a;$p;N;21,$D;ba' print the last 10 lines

If you are using a shell that supports process substitution, another way to accomplish this is to write to multiple processes, one for head and one for tail . Suppose for this example your input comes from a pipe feeding you content of unknown length. You want to use just the first 5 lines and the last 10 lines and pass them on to another pipe:

cat | < tee >(head -5) >(tail -10) 1>/dev/null> | cat 

The use of <> collects the output from inside the group (there will be two different programs writing to stdout inside the process shells). The 1>/dev/null is to get rid of the extra copy tee will try to write to it's own stdout.

That demonstrates the concept and all the moving parts, but it can be simplified a little in practice by using the STDOUT stream of tee instead of discarding it. Note the command grouping is still necessary here to pass the output on through the next pipe!

cat | < tee >(head -5) | tail -15 > | cat 

Obviously replace cat in the pipeline with whatever you are actually doing. If your input can handle the same content to writing to multiple files you could eliminate the use of tee entirely as well as monkeying with STDOUT. Say you have a command that accepts multiple -o output file name flags:

Источник

Cat last line linux

The UNIX School

Pages

Thursday, May 24, 2012

7 different ways to print the last line of a file in Linux

In an earlier article, we saw the different ways in which we can print the first line of a file. In this article, we will see the different ways in which we can print or display the last line or the trailer record of a file in Linux.

Let us consider a file with the following contents:

$ cat file Unix Solaris Linux

1. The tail is the most common command used. tail command prints the last part of the files. -1 specifies to print one line from the last part.

2. The END label in awk makes it even more easily. END label is reached once the entire file is parsed. Hence, on reaching END, the special variable $0 will be holding the last line of the file.

4. Another option in sed is to delete(d) all the lines other than(!) the last line($) which in turn prints only the last line.

5. In perl, every line being processed is saved in a variable. Same explanation as of awk. Only difference here is the scope of the variable $_ is only present in main, not in the END label. Hence, every line is stored in a variable and the same variable is used in the END.

6. tac command prints a file in reverse. By printing the first line of the tac output using the head, we will get the last line of the file printed. Not the best of options, but an option nevertheless.

7. Solution using a proper shell script. The file is processed using the while loop where each line is read in one iteration. The line is assigned to a variable x, and outside the loop, x is printed which will contain the last line of the file.

#!/bin/bash while read line do x=$line done < file echo $x

Источник

Оцените статью
Adblock
detector