Answers:
对于cut(1)
手册页:
请仅使用-b,-c或-f中的一个。每个LIST由一个范围或由逗号分隔的多个范围组成。所选输入的写入顺序与读取的顺序相同,并且仅写入一次。
它首先到达字段1,以便进行打印,然后到达字段2。
使用awk
来代替:
awk '{ print $2 " " $1}' file.txt
FS
是一个选择,OFS
是一个变量。例如awk -v OFS=";" -F"\t" '{print $2,$1}'
| sed 's/\r//' |
先将其通过管道传输到awk
awk '{print $4 "\t" $2 "\t" $6 "\t" $7}' file
您也可以结合cut
和paste
:
paste <(cut -f2 file.txt) <(cut -f1 file.txt)
通过评论:可以避免bashisms并通过执行以下操作删除cut的一个实例:
paste file.txt file.txt | cut -f2,3
cut
只要您具有唯一的列分隔符,就可以很好地用于变长列。
bash
isms并删除其中的一个实例cut
: paste file.txt file.txt | cut -f2,3
您可以为此使用Perl:
perl -ane 'print "$F[1] $F[0]\n"' < file.txt
运行perl的优点是(如果您知道Perl),与重新排列列相比,您可以在F上执行更多的计算。
perl -ae print
工作原理cat
为我
使用join
:
join -t $'\t' -o 1.2,1.1 file.txt file.txt
笔记:
-t $'\t'
在GNU join
更直观-t '\t'
没有的$
失败,(coreutils的 v8.28和更早?); 这可能是一个错误,必须采取类似的解决方法$
。请参阅:unix加入分隔符char。
join
即使只处理一个文件,也需要两个文件名。两次使用相同的名称会欺骗您join
执行所需的操作。
对于资源join
较少的系统,其占用空间比其他答案中使用的某些工具要小:
wc -c $(realpath `which cut join sed awk perl`) | head -n -1
43224 /usr/bin/cut
47320 /usr/bin/join
109840 /bin/sed
658072 /usr/bin/gawk
2093624 /usr/bin/perl
刚刚从事非常相似的工作,我不是专家,但我想我会分享我使用的命令。我有一个多列的csv,我只需要4列就可以了,然后我需要对其重新排序。
我的档案是管道'|' 定界,但可以换出。
LC_ALL=C cut -d$'|' -f1,2,3,8,10 ./file/location.txt | sed -E "s/(.*)\|(.*)\|(.*)\|(.*)\|(.*)/\3\|\5\|\1\|\2\|\4/" > ./newcsv.csv
诚然,它确实很粗糙且可以使用,但是可以进行调整以适合!
使用sed
与基本正则表达式的嵌套子表达式一起使用sed来捕获列内容并对其重新排序。在这种情况下,这种方法最适合用于有限数量的切割以对列进行重新排序的情况。
其基本思想是向与搜索图案的环绕有趣部分\(
和\)
,它可以在替换模式与被重放\#
,其中#
表示在搜索模式子表达式的顺序位置。
例如:
$ echo "foo bar" | sed "s/\(foo\) \(bar\)/\2 \1/"
产量:
bar foo
子表达式外部的文本将被扫描,但不会保留在替换字符串中以供播放。
尽管该问题并未讨论固定宽度的列,但我们将在此处进行讨论,因为这是对所提出的任何解决方案的有效衡量。为简单起见,尽管解决方案可以扩展到其他定界符,但我们假设文件是用空格定界的。
折叠空间
为了说明最简单的用法,我们假定可以将多个空格折叠成单个空格,并且第二列值以EOL终止(而不是填充空格)。
文件:
bash-3.2$ cat f
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 nl
0000040 s t r 2 sp sp sp sp sp sp sp 2 nl s t r
0000060 3 sp sp sp sp sp sp sp 3 nl
0000072
转变:
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f | od -a
0000000 C o l u m n 2 sp C o l u m n 1 nl
0000020 1 sp s t r 1 nl 2 sp s t r 2 nl 3 sp
0000040 s t r 3 nl
0000045
保留列宽
现在让我们将方法扩展到具有恒定宽度列的文件,同时允许列具有不同的宽度。
文件:
bash-3.2$ cat f2
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f2
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 sp
0000040 sp sp sp sp sp nl s t r 2 sp sp sp sp sp sp
0000060 sp 2 sp sp sp sp sp sp nl s t r 3 sp sp sp
0000100 sp sp sp sp 3 sp sp sp sp sp sp nl
0000114
转变:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r 2 sp sp sp sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
最后,尽管问题的示例没有长度不等的字符串,但此sed表达式支持这种情况。
文件:
bash-3.2$ cat f3
Column1 Column2
str1 1
string2 2
str3 3
转变:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3
Column2 Column1
1 str1
2 string2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r i n g 2 sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
与Shell下其他列重排序方法的比较
出乎意料的是,对于文件处理工具,awk不适合从字段切到记录结尾。可以使用正则表达式来完成此操作,例如\(xxx.*$\)
在哪里xxx
匹配列的表达式。
在内部shell脚本中实现时,使用粘贴和剪切子shell会很棘手。将命令行脚本中的代码带入Shell脚本后无法解析。至少这是我的经验(这促使我采用这种方法)。
cut
,不支持此直观的重新排序命令。无论如何,还有一个小窍门:你可以使用awk
的-FS
,并-OFS
选择使用自定义输入和输出字段分隔符(如-d
和--output-delimiter
的cut
)。