2

Considering a variable a describing temperature series for the city a. I have 9 directories (a1, a2, a3, a4, a5, a6, a7, a8, a9) each of them containing a table (respectively a1.txt, a2.txt, a3.txt, a4.txt, a5.txt, a6.txt, a7.txt, a8.txt, a9.txt).

I would like to move to another directory the table presenting the highest value at the first row and fourth column (with space separator). Does anyone know how to do that?

4 Answers 4

2

This is what I used to generate the files you're talking about:

mkdir -p       another/directory
for   n in     1 2 3 4 5 6 7 8 9
do    mkdir   -p "a$n"
      printf  "$n $n $n 1$n $n $n $n $n\n" >"a$n/a$n.txt"   #1 marks 4th col
done

This is what I used to mv the file:

 mv "a$(((a=$(t=$(printf \\t)
 paste a[1-9]/a[1-9].txt /dev/null |
 sed -e"s/\( *[^ ][^ ]*[ $t]\)\{4\}[^$t]*/\1/g;y| |\n|;q" |
 sort -rn | head -n1))-10))/a${a#1}.txt" another/directory

And this is what I did to verify I'd got it right:

cat another/directory/*

9 9 9 19 9 9 9 9

...but I didn't get it right. That depends on the highest value matching the file's name. This doesn't:

file=$(
    grep -n . ./a[1-9]/a[1-9].txt |
    grep :1: |     cut -d\  -f1,4 |
    sort -rnk2,2
)
mv "${file%%:*}" another/directory
1

This is not supposed to be a "write this program for me" site, so I am assuming that you have no idea where to start. So here's one way:

#!/bin/bash
highest=-999
for x in a[0-9]/a[0-9].txt;do
    fourth="$(awk 'NR==1{print $4}' $x)"
    if [ $highest -lt $fourth ];then
        highest=$fourth
        hifile=$x
    fi
done
echo "highest was $highest in $hifile"
mv $hifile high/

A brief of what the above code does: loops through all directory/file combinations named a[0-9]/a[0-9].txt it uses awk to assign the fourth field ({print $4}) from the first line (NR==1) to the variable fourth. It then compares if highest is less than fourth (if [ $highest -lt $fourth ];then), and if so saves the filename in the hifile variable. When the loop is done, it moves the file to the directory "high"

4
  • If none of the fourth-field values are higher than -999, you could end up with an undefined $hifile; consider priming $highest & $hifile with one of the input values. I'll have to remember the awk NR==1 part, though - thanks!
    – Jeff Schaller
    Nov 9, 2015 at 20:30
  • @jeff-schaller He said they would be temperatures, so -999 felt pretty safe. But point taken.
    – Mel
    Nov 9, 2015 at 21:29
  • @Mel Thank you this solution seems to work, but I have an issue with the line ´if [ $highest -lt $fourth ];then´ giving the error message "integer expression expected". Do you have an idea to workaround this around?
    – steve
    Nov 11, 2015 at 11:25
  • @steve sounds like you didn't set the initial value at the top highest=-999. You can either do that, or quote the values like: if [ "$highest" -lt "$fourth" ];then
    – Mel
    Nov 11, 2015 at 16:28
1

There's more than one way to do it, of course, but here's one way:

#!/bin/bash

# start out assuming 1 is the highest
highfile=a1/a1.txt
highval=$(head -1 a1/a1.txt | awk '{print $4}')
for a in `seq 2 9`
do
  val=$(head -1 a$a/a$a.txt | awk '{print $4}')
  if [ $val -gt $highval ]
  then
    highfile=a$a/a$a.txt
    highval=$val
  fi
done

echo mv $highfile destdir
1

It's quite a breeze with gawk

awk -v target_dir="$TARGET_DIR" '
  {a[FILENAME] = $4; nextfile}; 
  END{PROCINFO["sorted_in"]="@val_num_desc";
  for(k in a){system("mv "k" "target_dir); exit}}' */*.txt

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .