How keep last 50 lines in logfile

The problem is that your shell is setting up the command pipeline before running the commands. It's not a matter of "input and output", it's that the file's content is already gone before tail even runs. It goes something like:

  1. The shell opens the > output file for writing, truncating it
  2. The shell sets up to have file-descriptor 1 (for stdout) be used for that output
  3. The shell executes tail.
  4. tail runs, opens /home/pi/Documents/test and finds nothing there

There are various solutions, but the key is to understand the problem, what's actually going wrong and why.

This will produce what you are looking for,

echo "$(tail -n 50 /home/pi/Documents/test)" > /home/pi/Documents/test

Explanation :

  • $() is called command substitution which executes tail -n 50 /home/pi/Documents/test
  • the quotation marks preserve line breaks in the output.
  • > /home/pi/Documents/test redirects output of echo "$(tail -n 50 /home/pi/Documents/test)" to the same file.

Another solution to the file redirection clearing the file first is to use sponge from the moreutils packge like so:

tail -n 50 /home/pi/Documents/test | sponge /home/pi/Documents/test

This is because bash processes the redirection with the > first, deleting the contents of the file. Then it executes the command. Were you to use >>, the last 50 lines would be appended to the end of what's currently in the file. In this case, you'd have the same 50 lines repeated twice.

The command works as expected when redirecting to a different file. Here is one way to write the last 50 lines of a file to a file of the same name:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 && mv /home/pi/Documents/test2 /home/pi/Documents/test

This first writes the last 50 lines to a temporary file, which is then moved using mv to replace the original file.

As noted in the comments, this won't work if the file is still open. Moving the file also creates a new inode and may change ownership and permissions. A better way to do this using a temporary file would be:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 ; cat /home/pi/Documents/test2 > /home/pi/Documents/test

The temporary file can also be removed, though each time this happens its contents will be overwritten.