2

In a bash shell, I am trying to write a short one-liner to divide the line count of one file by the line count of another. I would like show at least two decimal places from floating-point division.

In other words, I would like a one-liner to print the percentage of one file's line count of another.

For example, if I have a first file (first.txt) with 25 lines and a second file (second.txt) with 100 lines, the one-liner would output .25.

Jake Sebright
  • 799
  • 8
  • 16

9 Answers9

3

The shortest I could come up with made use of command substitution and redirection

$ echo "scale=2; $(wc -l <first.txt) / $(wc -l <second.txt)" | bc
.25

Let me know if you have questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
3

First some test material:

$ for i in {1..25} ; do echo $i >> first ; done
$ for i in {1..100} ; do echo $i >> second ; done

Then some awk:

$ awk 'END{print(NR-FNR)/FNR}' first second
0.25

NR is the total number of records in both files. At the END FNRis the number of records in the latter file, so (NR-FNR)/FNR is the record count of the first file divided by the record count of the second.

Other than the solutions provided here, you need to take your question to the code golf course .

James Brown
  • 36,089
  • 7
  • 43
  • 59
2

alternatively, you could use gawk as:

gawk 'NR==FNR{a+=1;next} {b+=1} END{printf "%.2f\n", a/b}' first.txt second.txt
ewcz
  • 12,819
  • 1
  • 25
  • 47
0

The following stores the line counts of the two files in two variables. The filenames and leading whitespace are removed from the output of wc using sed and cut. The division is then performed on the two variables using bc.

count1=$(wc -l first.txt | sed -e 's/^[[:space:]]*//' | cut -f 1 -d ' ') && count2=$(wc -l second.txt | sed -e 's/^[[:space:]]*//' | cut -f 1 -d ' ') && echo "scale=2; $count1/$count2" | bc
Jake Sebright
  • 799
  • 8
  • 16
  • If you **redirect** the file's contents into `wc`, you don't have to parse out the filename. See David C. Rankin's answer – glenn jackman Sep 26 '17 at 21:15
0

Shortest version using bc and grep

echo "$(grep -c '$' file1) / $(grep -c '$' file2)" | bc -l
Munir
  • 3,442
  • 3
  • 19
  • 29
0

An alternate GNU awk answer, using a bunch of builtin variables :

gawk '
    ENDFILE {nr[FILENAME] = FNR} 
    END {printf "%.2f\n", nr[ARGV[1]] / nr[ARGV[2]]}
' first.txt second.txt
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
0

One time use

echo `wc -l <first.txt`/`wc -l <second.txt`|bc -l

One script use

e(){ echo `wc -l <$1`/`wc -l <$2` | bc -l;}
e first.txt second.txt

One user use: add function to .bashrc

Everyone use: add function to /etc/bash.bashrc

0
bash-4.4$ a=$(perl -e "print $(cat file1|wc -l) /$(cat file2|wc -l)")                                                                                                                   
bash-4.4$ echo $a                                                                                                                                                                   
0.333333333333333 

Edited the answer to support decimal values

abhishek phukan
  • 751
  • 1
  • 5
  • 16
0

An alternative to all the bc answers:

dc <<< "2k $(wc -l < file1) $(wc -l < file2) /p"

The 2k sets the precision, here the output will always have two decimal places.

Socowi
  • 25,550
  • 3
  • 32
  • 54