So i have a file with column that has information on salary (eg. 2674 dollars) -

indi  salary
   sam    2674
   john   6375
   max    9547

and another file with the scale of the salary (column1&colum2) on its corresponding rank (column3)

salary_min salary_max Rank
2000           4000    Deputy
4000           6000    secretary
6000           8000    Assistant
8000           10000   Manager

Now I would like to assign those individuals from file 1 based on the salary to their corresponding rank

so the final output would be

    indi    Rank
     sam    Deputy
     john   Assistant
     max    Manager

How can I achieve this in linux on the same dataset type but with larger data?

  • You may want to insert this data to a database and than query. If it is a large dataset, any other method might be too slow. – Mehmet Dec 15 '14 at 13:56

Assuming that salaries and salary bounds are always going to be integers and that salary ranges are non-overlapping, here's something that might work (in bash)

{ printf "indi Rank\n" ; 
join -o1.1,2.2 <(tail -n +2 file1 | sort -b -k2,2) -1 2 -2 1 \
<(awk 'FNR > 1{for (i=$1; i<$2; ++i) printf "%d %s\n", i, $3}' file2 | sort -k1,1) ;}
indi Rank
sam Deputy
john Assistant
max Manager

I wouldn't recommend it on a huge chunk of data, but I thought I'd try a bash solution. I'm not very bash-fluent, but this seems like the "obvious" way of handling things, "algorithmically speaking". This basically iterates over each file and searches for the good range. I've given some details in the comments.

The script must be executed this way:

$ ./script.sh [salaries] [ranges]

The salaries file contains Sam's, John's and Max's salaries, while ranges contains your ranges and ranks (2000 to 4000 is deputy, 4000 to 6000 is secretary, and so on).


test $# -ne 2 && exit 1
test ! -r "$1" -o ! -r "$2" && exit 2

# Open the salary file (3) and the ranges (4).
exec 3< "$1"
exec 4< "$2"

# Echo the salary headers.
read -d$'\n' headers <&3
echo "$headers" | tr -s ' '

# For each line in the salary file...
while read name salary; do
    # Skip the ranges headers ("salary_min...").
    read -d$'\n' skip <&4

    # For each range...
    while read min max rankname; do
    # If the salary is within the range, print name and rank.
    if [ "$salary" -ge $min -a "$salary" -lt $max ]; then
        echo "$name $rankname"
    done <&4

    # Reopen the range file for the next employee.
    exec 4>&-
    exec 4< "$2"
done <&3

exit 0

Note that my ranges checks are inclusive on the lower bound, but exclusive on the higher:

[ "$salary" -ge $min -a "$salary" -lt $max ]

You might want to change this line if it isn't the behaviour you're expecting. I also tried to open files as rarely as possible, but since bash does not handle file seeking, I still need to close/reopen the ranges file regularly. To be honest, I'd recommend a slightly lower level implementation, if you are to deal with very large files. C would be nice.

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.