dispepsi
dispepsi

Reputation: 270

awk: sort file based on user input

I have this simple awk code:

awk -F, 'BEGIN{OFS=FS} {print $2,$1,$3}' $1

Works great, except I've hardcoded how I want to sort the comma-delimited fields of my plaintext file. I want to be able to specify at run time in which order I'd like to sort my fields.

One hacky way I thought about doing this was this:

read first
read second
read third

TOTAL=$first","$second","$third

awk -F, 'BEGIN{OFS=FS} {print $TOTAL}' $1

But this doesn't actually work:

awk: illegal field $(), name "TOTAL"

Also, I know a bit about awk's ability to accept user input:

BEGIN {
    getline first < "-"
}

$1 == first {
}

But I wonder whether the variables created can in turn be used as variables in the original print command? Is there a better way?

Upvotes: 2

Views: 78

Answers (2)

Ed Morton
Ed Morton

Reputation: 204164

All you need is:

awk -v order='3 1 2' 'BEGIN{split(order,o)} {for (i=1;i<=NF;i++) printf "%s%s", $(o[i]), (i<NF?OFS:ORS)}'

e.g.:

$ echo 'a b c' | awk -v order='3 1 2' 'BEGIN{split(order,o)} {for (i=1;i<=NF;i++) printf "%s%s", $(o[i]), (i<NF?OFS:ORS)}'
c a b

$ echo 'a b c' | awk -v order='2 3 1' 'BEGIN{split(order,o)} {for (i=1;i<=NF;i++) printf "%s%s", $(o[i]), (i<NF?OFS:ORS)}'
b c a

Upvotes: 0

chepner
chepner

Reputation: 531918

You have to let bash expand $TOTAL before awk is called, so that awk sees the value of $TOTAL, not the literal string $TOTAL. This means using double, not single, quotes.

read first
read second
read third

# Dynamically construct the awk script to run
TOTAL="\$$first,\$$second,\$$third"
SCRIPT="BEGIN{OFS=FS} {print $TOTAL}"

awk -F, "$SCRIPT" "$1"

A safer method is to pass the field numbers as awk variables.

awk -F, -v c1="$first" -v c2="$second" -v c3="$third" 'BEGIN{OFS=FS} {print $c1, $c2, $c3}' "$1"

Upvotes: 3

Related Questions