0

I wonder if there is a way to remove half the lines of a file using wc and sed.

I can do this:

sed -i '50,$d' myfile.txt

Which removes lines from 50 to the end of file. I can also do this:

wc -l myfile.txt

Which returns the number of lines in the file.

But what I really want to do is something like this:

wc -l myfile.txt | sed -i '{wc -l result}/2,$d' myfile.txt
  1. How can I tell sed to remove the lines starting from the wc -l result divided by 2?
  2. How can I do this recursively?
danielrvt
  • 9,472
  • 16
  • 73
  • 115
  • 1
    use `d` to delete lines, `r` command is used to append text from another file... try `sed -i $(( $(wc -l – Sundeep Dec 10 '19 at 13:27

3 Answers3

2

you can make use of head command:

head -n -"$(($(wc -l<file)/2))" file

awk is also possible, and with exit statement, it could be faster:

awk -v t="$(wc -l <file)" 'NR>=t/2{exit}7' file

You can get the file by awk/head ... > newFile or cmd > tmp && mv tmp file to have "in-place" change.

Kent
  • 181,427
  • 30
  • 222
  • 283
1

I guess you were close. Just use a command substitution with arithmetic expansion to get the value of the starting line:

startline="$(( $(wc -l <myfile.txt) / 2 ))"
sed -i "$startline"',$d' myfile.txt

Or a oneliner:

sed -i "$(( $(wc -l <myfile.txt) / 2 ))"',$d' myfile.txt
KamilCuk
  • 96,430
  • 6
  • 33
  • 74
1

In some sense, reading the file twice (or, as noted by Kent, once and a half) is unavoidable. Perhaps it will be slightly more efficient if you use just a single process.

awk 'NR==FNR { total=FNR; next }
    FNR>total/2 { exit } 1' myfile.txt myfile.txt

Doing this recursively with Awk is slightly painful. If you have GNU Awk, you can use the -t inline option, but I'm not sure of its semantics when you read the same file twice. Perhaps just fall back to a temporary output file.

find . -type f -exec sh -c "awk 'NR==FNR { total=FNR; next }
    FNR>total/2 { exit } 1' {} {} >tmp &&
  mv tmp {}" _ \;
tripleee
  • 158,107
  • 27
  • 234
  • 292