我有一个文本文件:
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中的文本文件进行排序,同时将标题保留在顶行。
此外,如果我可以整合文本文件以使列排成一行,那也很好。但我不确定该怎么做。
我已经研究过并试过这些,但都没有用过:
cat q2.txt | (read -r; printf "%s\n" "$REPLY"; sort -nk3)
head -n 1 q2.txt && tail -n +2 q2.txt | sort -nr -k1
(上面文件的名称是q2.txt
。)
答案 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; : - 使用分号作为分隔符创建一个列表,以在
上排列数据