3

In Ubuntu desktop 20.04, I have 20 directories, each containing a text file with the same name, "weights". These text files contain ~20-30 numbers separated with a space. In each of the 20 directories, there is also a text file named "coefficient", which contains a single number.

I want to execute a shell command that goes into each directory, sums together all the numbers in the "weights" text file, and multiplies that sum by the number in the "coefficient" text file. If there was some way for this to be put into a csv that would be ideal, but even if it just prints to the terminal that would be okay too!

1
  • 1
    Thanks, I have now added this!
    – BennyD
    May 11, 2020 at 21:48

2 Answers 2

2

Perl to the rescue!

perl -wle '
    for my $dir (@ARGV) {
        my $s = 0;
        open my $w, "<", "$dir/weights" or die "$dir: $!";
        $s += $_ for split " ", <$w>;
        open my $c, "<", "$dir/coefficient" or die "$dir: $!";
        print $s * <$c>;
}' -- */
  • -w turns on warnings
  • -l removes newlines from input and adds them to output
  • the argument */ is expanded by the shell to all the directory names in the current directory (you can specify path/to/parent/directory/*, too)
  • open opens a file, "<" means for reading, $w and $c are the corresponding file handles
  • the diamond operator <$w> reads a line from the given file handle
3
  • Brilliant! Thank you thank you thank you!
    – BennyD
    May 12, 2020 at 3:15
  • As a followup, is there a way to then compile each of these into a single csv?
    – BennyD
    May 12, 2020 at 4:28
  • Just append | sed '$!a,' | tr -d '\n'.
    – choroba
    May 12, 2020 at 9:52
0

bash, coreutils and bc

You can generate the arithmetic expression with the standard programs like this:

for dir in *; do 
  printf "("
  tr ' ' + < $dir/weights | tr -d '\n'
  printf ") * "
  printf "%s\n" $(<$dir/coefficient)
done | bc -l

Note this assumes you do not have extraneous white space in your files.

Demo

Generate sample data

mkdir -p testdir/{a..z}
cd testdir
for dir in *; do 
  n=$(shuf -r -i 20-30 -n1)
  shuf -r -i 0-100 -n $n | paste -d' ' -s > $dir/weights
  seq 0 .01 1 | shuf -n1 > $dir/coefficient
done

Output when script is run in testdir/

1214.19
970.97
776.03
449.48
803.76
696.01
514.71
789.36
169.44
615.50
972.48
688.50
1290.76
635.97
824.90
787.39
83.36
1048.32
956.25
203.36
1144.66
327.70
65.40
367.68
828.80
919.75

Append | paste -d, -s to bc if you want the output to be comma-separated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.