Score:0

Cut last two lines of a file and append to another file repeatedly

br flag

I tried the following command to cut out the last two lines of a file and append them to a new file

tail -n -2 file1 >> file2 && head -n -2 file1 > tmp && mv tmp file1

With the above code on every manual execution, the last two lines of file1 get cut out and append to file2. But what would be the best way to do that automatically until file1 has no more entries to cut out?

Or even do you have a method to do this in a completely different way?

HuHa avatar
es flag
This looks suspiciously like a homework assignment, not a real life problem.
diggidre avatar
br flag
@HuHa believe me its a real life problem :)
Score:1
hr flag

IMHO it would be simpler to read pairs of lines in reverse order using tac

tac file1 | while IFS= read -r a && IFS= read -r b; do printf '%s\n%s\n' "$b" "$a"; done >> file2

(this will terminate when there are fewer than 2 lines left in file1 - thanks u/artur meinild) or

tac file1 | sed -E '$!N;s/(.*)\n(.*)/\2\n\1/' >> file2

(which will continue to the end of file1 even if it has an odd number of lines1).

Or a similar method using GNU parallel:

tac file1 | parallel -N2 "printf '%s\n'" '{2}' '{1}' >> file2

  1. if you want to use sed, but ignore a trailing odd line as the while-loop version does, change to sed -nE '$!N;s/(.*)\n(.*)/\2\n\1/p' which only prints on successful substitution
Artur Meinild avatar
vn flag
Your first option does not work if `file1` has an odd number of lines - then the first line isn't transferred to `file2` as the last line. However, the question didn't mention if this should be the case, but I thought it should. I didn't test with `parallel`. I still upvoted though.
hr flag
@ArturMeinild good point - let's see if the OP clarifies their question
Score:0
kr flag
dhm

This can be done with a single awk command:

tac input_file | awk 'NR%2==0{print $0"\n"second};NR%2==1{second=$0}'
Score:0
vn flag

This is the beginner friendly version, using a script with a while loop that is easy to read and understand:

#!/bin/bash

# Do this operation as long as file1 has content
while [[ -n $(cat file1) ]]
do
  # Put the 2 last lines of file1 in file2
  tail -n -2 file1 >> file2
  # Remove the last 2 lines of file1
  head -n -2 file1 > tmp && mv -f tmp file1
done

# If you want to remove the empty file1
# rm -f file1

This solution works even if file1 has an odd number of lines (then the first line of file1 will be the last line of file2).

Score:0
br flag

OK guys thx for your suggestions. I tried all the day and struggled with some code but finally I have my solution working. What are your thoughts about... I do a until loop similar to what Arthur Meinild mentioned.

until ! [ -s file_tmp ]; do
tail -n -2 file_tmp >> file.tmp && seq 2 | xargs -i sed -i -e '$d' file_tmp
done
rm file_tmp && cat file.tmp >> file
rm file.tmp

I had other solutions with head instead of sed but head turns out way more heavy disk io. The steeldriver version from above seems also interesting to me but for now I will go the sed way :)

Score:0
kr flag
dhm

You can do this with three commands.

(seq 10 provides a sample input file)

seq 10 | sed  -n '1~2p' | tac > odds
seq 10 | sed  -n '2~2p' | tac > evens
awk  '{getline line < "evens"; print $0; print line}'  odds

9
10
7
8
5
6
3
4
1
2
Score:0
jp flag

With awk, you can e.g save the file lines to an array then set a counter(to be used to call the indexes of the array in reverse) that you decrement by two after each print action while printing tow lines at a time in their original order within an if ... else .. to handle files with both odd or even line numbers like so:

awk '{ a[i++]=$0 } END {
       for (l=i-1; l>=0; l=l-2) {
       if (l > 0) {
       print a[l-1]"\n"a[l] 
       } else {
       print a[l]
    }}}' file1 > file2
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.