Variables are not expanded in single quoted strings. There's no way around this.
In this case, you want to output the three first lines of your data as is, and sort the rest. For simplicity, I would do this with
sort_opts=( -k3,3r -k2,2 -k1,1r )
{ head -n 3 file
awk 'NR > 3' file | sort "${sort_opts[@]}" -t '~' } >newfile
If you feel that you really want to do the sorting from within awk
, and assuming that $IFS
remains unchanged with a space as its first character:
sort_opts=( -k3,3r -k2,2 -k1,1r )
awk -v sort_opts="${sort_opts[*]}" '
BEGIN { sortcmd = sprintf("sort %s -t \"~\"", sort_opts) }
NR <= 3 { print; next } { print | sortcmd }' file >newfile
This gives the sorting options to awk
using -v
on the command line, the BEGIN
block creates the sorting command to use as a string in the sortcmd
variable, and this is then used in the last block (triggered for lines 4 on-wards).
Note that when using print
with a pipe in awk
, the right hand side of the pipe must be a string representing the shell command to pipe to. This is not the case in your code, which is why you get an "illegal statement" error.
When values that you need to import into awk
contains backslashes, you may want to use an environment variable instead (to avoid having to double up each backslash):
sort_opts=( -k3,3r -k2,2 -k1,1r )
SORT_OPTS="$sort_opts[*]" awk '
BEGIN { sortcmd = sprintf("sort %s -t \"~\"", ENVIRON["SORT_OPTS"]) }
NR <= 3 { print; next } { print | sortcmd }' file >newfile
sort
command, whichawk
knows nothing about.