Seu comando
head -n 10 filename | tail -n 5 filename
é sem sentido. A saída de head nunca será lida por tail , pois tail já está lendo diretamente de filename . Portanto, o resultado é exatamente o mesmo que com apenas
tail -n 5 filename
O utilitário head é usado para obter um determinado número de linhas do topo do arquivo (ou, com GNU head , todas as linhas do arquivo, exceto por um certo número de linhas contando a partir do final do arquivo). O utilitário head não é o que você deseja usar para obter o final dos dados de um arquivo. Para isso, use tail como você mostrou.
Qualquer outra solução seria mais complexa que seu tail -n 5 básico.
Por exemplo:
tac filename | head -n 5 | tac
que assume que um tem tac de GNU coreutils instalados. Tanto o head quanto o tail serão instalados em qualquer sistema que tenha um ambiente shell compatível com POSIX remotamente, enquanto o tac será encontrado apenas em sistemas Linux e outros sistemas onde o GNU Coreutils tenha sido instalado.
Você também pode implementar seu próprio tail em awk se for tail e não quiser usá-lo:
$ awk -vn=5 '{ lines[i++ % n] = $0 } END { for (j = 0; j < n; ++j) print lines[(i+j)%n] }' filename
fffff
ggggg
hhhhh
iiiii
jjjjj