Question: There are unknown number of lines in a file. How to delete nth line (when counted from the bottom) with one-liner command (you may use more than one if it is necessary) on Unix platform.

Answer: 
Pure `sed`:

* If *n* is 1:

```
sed '$ d'

```

This is simple: if it's the last line, delete the pattern space, so it's not printed.
* If *n* is greater than 1 (and available as `$n`):

```
sed "
   : start
   1,$((n-1)) { N; b start }
   $ { t end; s/^//; D }
   N
   P
   D
   : end
 "

```

Note `$((n-1))` is expanded by the shell before `sed` starts.

This fragment

```
: start
1,$((n-1)) { N; b start }

```

stores *n*-1 lines in the pattern space. If `sed` reaches the end of the input stream during this loop, the pattern space will be printed automatically (there is no n-th line from the end, no line will be deleted).

Suppose there is more input. Then, before we get to the last line, this fragment is iterated:

```
N   # read the next line of input and append it to the pattern space
P   # print the first line from the pattern space
D   # delete the first line from the pattern space and start a new cycle

```

This way the pattern space is our buffer which makes the output several lines "late" according to the input. `N` from this fragment is able to read the last line of the input as well.

After the last line is read, this gets executed:

```
$ { t end; s/^//; D }

```

When this code is executed for the first time, `t` doesn't branch to `end` because there was no successful substitution before. Such no-op substitution `s/^//` is then performed and the first line from the pattern space is deleted (`D`) without being printed. This is exactly the line you want to be deleted. Since `D` starts a new cycle, the same line of code will eventually be executed again. This time `t` will branch to `end`.

When `sed` reaches the end of the script, the pattern space is printed automatically. This way all remaining lines get printed.

The command will generate the same output for `n=2` (valid) and `n=1` (invalid). I tried to find a single solution that works regardless of *n*. I failed, hence the special case when your *n* is 1.
You can combine `head` and `tail` to achieve this.

If the *nth* line from the bottom needs to be deleted

1. `head` reads from standard input and reports to standard output *total -n* lines from the top
2. `tail` reads and reports to standard output the bottom *n-1* lines from standard input.
3. Taken as a whole, the lines are thus reported to standard output in order, with the \*nth` line from the end being skipped

This solution depends on `head` leaving the file offset of the open file description just after the last reported line - I believe GNU `head` does indeed do this when standard input is redirected from a file

```
n=200; tmpfile=$(mktemp) && { head -n -$n; tail -n -$((n-1)); }<file >"$tmpfile" \
    && mv -- "$tmpfile" file

```