Bash 如何编写shell脚本来交换txt文件中的列?

Bash 如何编写shell脚本来交换txt文件中的列?,bash,shell,scripting,Bash,Shell,Scripting,我在试着解决我的一个旧任务我真的被困在这个任务中了有人能帮我吗 有一个名为datafile的文件。此文件包含一些朋友及其好友的姓名 年龄。但不幸的是,名称的格式不正确。他们应该是 姓 但是,错了,他们是姓,姓 问题的任务是编写一个名为fix_datafile的shell脚本 要更正此问题,请按字母顺序对名称进行排序。更正的文件名 名为datafile.fix 请确保文件的原始结构保持不变 以下是datafile.fix文件的示例: 个人信息 ********姓名****************年

我在试着解决我的一个旧任务我真的被困在这个任务中了有人能帮我吗

有一个名为datafile的文件。此文件包含一些朋友及其好友的姓名

年龄。但不幸的是,名称的格式不正确。他们应该是

但是,错了,他们是姓,姓

问题的任务是编写一个名为fix_datafile的shell脚本

要更正此问题,请按字母顺序对名称进行排序。更正的文件名

名为datafile.fix

请确保文件的原始结构保持不变

以下是datafile.fix文件的示例:

个人信息

********姓名****************年龄*****

亚历山德罗维奇,富兰克林47

Amber,Christine 54

福兰克33苹果

阿塔博厄尔,阿尔曼18

巴拉德,乔治38

巴拉德,山姆19

谢尔萨米奇,22岁

鲍杰克,史蒂文33

尚特尔,亚历克斯60

道尔,杰弗里45

法兰,帕梅拉40

亨德曼,吉米23

卡什曼,杰尼弗25

凯斯汀,艾伦33

洛鲁克斯,艾伦29

纽约州马蒂斯26号

麦克斯特,杰弗里31

牛顿,格里沙40

奥萨马,富兰克林33

奥萨纳,加布里埃尔61

乔治·奥克斯纳德20

帕洛马尔,弗兰克24

普洛默,苏珊29

约翰·普朗克31

罗切斯特,本杰明40

维罗纳斯坦诺克38

特内西克,加布里埃尔29

嗯,Elsa 21

如果你可以使用awk,我想你可以,那么有一个脚本可以满足你的需要:

#!/bin/bash
RESULT_FILE_NAME="datafile.new"
cat datafile.fix | head -4 > datafile.new
cat datafile.fix | tail -n +5 | awk -F"[, ]" '{if(!$2){print()}else{print($2","$1, $3)}}' >> datafile.new
传递-F[,]允许awk按空格和空格拆分列,剩下的只是以所需格式打印列。缺点是我们应该使用if语句来保留空行,文件头也应该单独处理

另一种选择是使用sed:

缺点是它需要的正则表达式没有awk语法那么明显。

如果你可以使用awk,我想你可以,那么有一个脚本可以满足你的需要:

#!/bin/bash
RESULT_FILE_NAME="datafile.new"
cat datafile.fix | head -4 > datafile.new
cat datafile.fix | tail -n +5 | awk -F"[, ]" '{if(!$2){print()}else{print($2","$1, $3)}}' >> datafile.new
传递-F[,]允许awk按空格和空格拆分列,剩下的只是以所需格式打印列。缺点是我们应该使用if语句来保留空行,文件头也应该单独处理

另一种选择是使用sed:

缺点是它需要的正则表达式不如awk语法那么明显

一艘班轮:

awk -F[,\ ] '!/^$/ && !/^#/ { first=$1;last=$2;map[first][last]=$0 } END { PROCINFO["sorted_in"]="@ind_str_asc";for (i in map) { for (j in map[i]) { print map[i][j] } } }' namesfile > datafile.fix
完全处于呆滞状态的解决方案

将字段分隔符同时设置为、和空格。然后忽略任何空行或以开头的行。根据分隔字段标记第一个和最后一个变量,然后创建一个二维数组,名为map,按名字和姓氏索引,值等于行。最后,将sort设置为index字符串升序,并按请求的顺序在数组中循环打印名称

一艘班轮:

awk -F[,\ ] '!/^$/ && !/^#/ { first=$1;last=$2;map[first][last]=$0 } END { PROCINFO["sorted_in"]="@ind_str_asc";for (i in map) { for (j in map[i]) { print map[i][j] } } }' namesfile > datafile.fix
完全处于呆滞状态的解决方案


将字段分隔符同时设置为、和空格。然后忽略任何空行或以开头的行。根据分隔字段标记第一个和最后一个变量,然后创建一个二维数组,名为map,按名字和姓氏索引,值等于行。最后,将排序设置为索引字符串升序,并按请求的顺序在数组中循环打印名称。

我已经尝试使用awk和sed。 试试看这是否管用

less dataflie.fix | sed 's/ /,/g' | awk -F "," '{print $2,$1,$3}' | sed 's/ /,/' | sed 's/^,//' | sort -u  > dataflie_new.fix

我试过使用awk和sed。 试试看这是否管用

less dataflie.fix | sed 's/ /,/g' | awk -F "," '{print $2,$1,$3}' | sed 's/ /,/' | sed 's/^,//' | sort -u  > dataflie_new.fix
完全在bash中:

re=^[:space:]*[^][:space:].[:alpha:]+,[:space:].[:alpha:].[:alpha:]*[:alpha:].[:digit:]]+ 读行时 做 如果[${line}=~$re]] 然后 echo${BASH_重赛[3]},${BASH_重赛[1]}${BASH_重赛[5]} 其他的 echo${line} fi done在bash中完全忽略:

re=^[:space:]*[^][:space:].[:alpha:]+,[:space:].[:alpha:].[:alpha:]*[:alpha:].[:digit:]]+ 读行时 做 如果[${line}=~$re]] 然后 echo${BASH_重赛[3]},${BASH_重赛[1]}${BASH_重赛[5]} 其他的 echo${line} fi done其核心是使用[[命令、括号分组和bash_重新匹配数组的bash regex matching=~操作符,捕获逗号[^][:space:][]+。名正则表达式的构造是为了排除注释,姓正则表达式的构造是为了处理年龄之前的多个空格,而不将它们包含在名称中。前提条件:带或不带前导空格的注释行^[[:space:]*[^],或不带逗号的行,以不变的方式传递。名字或姓氏可能有内部空格。一旦姓氏和姓氏被隔离,就可以很容易地按相反顺序打印它们,后跟age echo${BASH_REMATCH[3]}、${BASH_REMATCH[1]}${BASH_REMATCH[5]}。请注意,字母/空格分组被视为匹配项,这就是我们跳过2和4的原因。

应该是bash脚本还是可以使用例如python?应该是bash?你能帮我吗?你能使用awk吗?我不这么认为。请帮我解决这个问题。我从早上起就一直在坚持我已经实现了awk和sed解决方案,我认为sed更好这种情况下,因为它不需要额外的努力来保存文件结构。它应该是bash脚本还是可以使用例如python?它应该是bash,你能帮我吗?你能使用awk吗?我不这么认为。请帮我解决这个问题。我从早上起就一直被卡住了。我已经实现了awk和sed解决方案,我认为sed在这种情况下更好,因为它不需要额外的努力来保留文件结构。sed可以做什么?将有一个类似于awk的表达式,但使用sed。它只是另一个测试处理器,没有什么大的区别。只是添加了一个使用sed的解决方案。它工作得更好,因为它保留了文件结构。不需要cat和head当使用awk时,awk可以为您完成所有这些处理。sed可以做什么?将有一个类似于awk的表达式,但使用sed。它只是另一个测试处理器,没有什么大的区别。只是添加了一个使用sed的解决方案。它工作得更好,因为它保留了文件结构。当使用awk时,不需要使用cat和headawk可以为您完成所有这些处理。尽量减少管道,因为这会导致效率低下。不需要向sed输送管道,以后再向sed输送。尽量减少管道,因为这会导致效率低下。不需要向sed输送管道,以后再向sed输送管道。。