如何对文本文件进行整理并对其进行排序,同时将标题保留在顶部

时间:2017-03-10 05:07:33

标签: bash sorting

我有一个文本文件:

Name    Local   International   Total

Victoria University 17969   9199    27168

University of Wollongong    18194   12360   30554

University of Western Sydney    37531   4333    41864

University of Western Australia 20596   5241    25837

University of Technology Sydney 27584   10054   37638

University of Tasmania  21940   4872    26812

University of Sydney    42028   12278   54306

University of Sunshine Coast    9546    1210    10756

University of Southern Queensland   21536   5183    26719

University of South Australia   25520   7428    32948

University of Queensland    37252   11519   48771

University of Notre Dame Australia  10633   327 10960

还有更多的大学,但我假设你不需要全部阅读 - 你明白了。

我希望按照国际学生的数量对bash中的文本文件进行排序,同时将标题保留在顶行。

此外,如果我可以整合文本文件以使列排成一行,那也很好。但我不确定该怎么做。

我已经研究过并试过这些,但都没有用过:

  1. cat q2.txt | (read -r; printf "%s\n" "$REPLY"; sort -nk3)
    
  2. head -n 1 q2.txt && tail -n +2 q2.txt | sort -nr -k1
    
  3. (上面文件的名称是q2.txt。)

3 个答案:

答案 0 :(得分:0)

这个问题更适合awk或perl;无论如何,我写了这个脚本,没有经过充分测试,可能还有很大的改进空间。基本上,它读取内存中的文件以便能够处理字段。然后,它构造一个文件(名为neattmpsort)以通过排序处理,然后它读回有序索引以打印出最终排序表。脚本中有注释和一些调试指令(因为这是我第一次在bash中使用数组)。

# use 4 arrays to store name, nloc, ninter, ntotal
declare -a name
declare -a nloc
declare -a ninter
declare -a ntotal

nrecord=0
while read -a line; do
  let nrecord=$nrecord+1
  # echo "$nrecord: ${line[*]}"
  # assign fields. calculate number of words
  nfields=${#line[@]}
  let nfields=$nfields-1
  ntotal[$nrecord]=${line[$nfields]}
  let nfields=$nfields-1
  ninter[$nrecord]=${line[$nfields]}
  let nfields=$nfields-1
  nloc[$nrecord]=${line[$nfields]}
  #let nfields=$nfields-1
  uniname="${line[@]:0:$nfields}"
  # echo "uniname: $uniname"
  name[$nrecord]="$uniname"

  # echo "nloc=${nloc[2]} ninter=${ninter[2]} ntotal=${ntotal[2]}"
done < q2.txt

# now the file is read in. Construct a special file to
# be processed by sort, using ninter
[ -f neattmpsort ] && rm neattmpsort
for (( i=2; i<=${#ninter[@]}; i++ )); do
  echo "${ninter[$i]} $i" >> neattmpsort
done
# sort this file, which contains ninter and original record
# also read back the correct positions
declare -a sorted
while read sortkey origrec; do
  sorted+=($origrec)
  #echo "read sort $origrec"
done < <(sort -n neattmpsort)

#echo "sorted: ${sorted[@]}"
#read key

# now the final output
# header
echo -e "Name \t\t\t\t\t Local \t International \t Total"
for (( i=1; i<=${#sorted[@]}; i++ )); do
  kp=${sorted[$i]}
  # format name
  uniname="${name[$kp]}"
  while [ ${#uniname} -lt 36 ]; do uniname="$uniname "; done
  echo -ne "$uniname \t"
  echo -en " ${nloc[$kp]} \t"
  echo -en " ${ninter[$kp]} \t\t"
  echo -e  " ${ntotal[$kp]}"
done

上述数据的结果是:

Name                                     Local   International   Total  
University of Sunshine Coast             9546    1210            10756  
University of Western Sydney             37531   4333            41864
University of Tasmania                   21940   4872            26812
University of Southern Queensland        21536   5183            26719
University of Western Australia          20596   5241            25837
...

我希望它有所帮助。通过修改脚本,可以对输出进行不同的格式化。

答案 1 :(得分:0)

首先,我在右边的最后三个字段的每一个之前打印了一个冒号,使用冒号作为字段分隔符,我们可以根据第三个字段进行排序,最后我从输出中删除了冒号:

HEADER=`head -1 input.txt | sed 's/\s\+/;/g'`
BODY=`cat input.txt | awk 'BEGIN { ORS="" } NR>1 && NF{ for(i=1;i<=NF;i++){if(i > NF-3) print ";"$i" "; else print $i" "} print "\n" }' | sort -t';' -k3 -n`
echo -e "$HEADER\n$BODY" | column -t -s';'

标题已保存,并在最后单独打印。

输出:

Name                                Local   International  Total
University of Sunshine Coast        9546    1210           10756 
University of Western Sydney        37531   4333           41864 
University of Tasmania              21940   4872           26812 
University of Southern Queensland   21536   5183           26719 
University of Western Australia     20596   5241           25837 
Victoria University                 17969   9199           27168 
University of Technology Sydney     27584   10054          37638 
University of Sydney                42028   12278          54306 
University of Wollongong            18194   12360          30554 

答案 2 :(得分:0)

sed -r '1{s/ +/;/g};2,${/./s/ +([0-9])/;\1/g}' file | sort -n -t';' -k3 | column -t -s';'

不漂亮,但有效:)

说明:

-r: - 允许您使用()进行分组而不转义它们。也可以使用+无逃避

1 {s / + /; / g}: - 将一个或多个空格的所有集合更改为第1行的分号

2,$ {...}: - 从第二行直到文件末尾执行{}

之间的所有操作

/./: - 只考虑非空行

s / +([0-9])/; \ 1 / g: - 假设上面的情况属实,找到一个或多个空格,后跟一组数字(保存数字),然后用分号替换通过保存的数字

sort -n -t&#39;;&#39; -k3: - 按分号

分隔的第三个字段按数字排序

列-t -s&#39;;&#39; : - 使用分号作为分隔符创建一个列表,以在

上排列数据