我已经问得差不多了已经有同样的问题了,但这一次,我想找回X最新的CSV 文件的一行元素。例如,输入文件如下:
1;foo;bar;baz;x;y;z
2;foo;bar;baz;x;y;z
3;foo;bar;baz;x;y;z
cut
获取最后两列的命令是什么(最终使用),所以我得到:
y;z
y;z
y;z
事实上,我真正的目标是检索前 3 个和每行的最后 2 个字段,所以我得到:
1;foo;bar;y;z
2;foo;bar;y;z
3;foo;bar;y;z
不幸的是,我无法使用类似的命令cut -d \; -f 1-3,10-11
(如果行中有 11 个元素),因为 CSV 文件不遵循真实的CSV 格式。事实上,行中间的一些字段是加密的,它们的加密值有时可能包含一个;
字符(当然,它们没有包装在 里面"
)。换句话说,我的台词可能是这样的:
1;foo;bar;#@$"é&^l#;baz;x;y;z
2;foo;bar;#¤=é;)o'#;baz;x;y;z
3;foo;bar;#]]'~é{{#;baz;x;y;z
正如你所看到的,在第二行,有一个额外的;
字符,所以我不能在这里使用像 这样的命令cut -d \; -f 1-3,7-8
,因为 if 会返回该字符,这是错误的:
1;foo;bar;y;z
2;foo;bar;x;y (-> Wrong here, there is a shift)
3;foo;bar;y;z
那么我该如何使用cut
来解决我的问题呢?
谢谢
ps:我特别喜欢这个cut
命令,所以如果你有一个命令可以做我想要的事情,但事实并非如此cut
,那么也没关系:)
编辑值得注意的是,这台机器相当旧了:uname -a
给出以下消息:
SunOS ###### 5.10 Generic_142900-05 sun4u sparc SUNW,Sun-Fire-V240
并且某些命令可能不存在(例如rev
)
答案1
在你的版本SunOS
nawk
(或就此而言awk
)应该能够做到这一点
nawk -F';' 'BEGIN{OFS=";"}{print($1,$2,$3,$(NF-1),$(NF))}' file.txt
答案2
cut
这是一个多命令解决方案,用于仅使用, rev
(用于逆向)和 shell 内置命令来检索前 3 个和最后 2 个字段:
while read line
do
first=$(echo -n "$line" | cut -d ";" -f -3)
second=$(echo -n "$line" | rev | cut -d ";" -f -2 | rev)
echo "$first;$second"
done < my_file
当然,这些语句也可以放在一行中。
编辑:
我收集了一些单行替代方案rev
(省略了打印最终的'\n'):
Python:python -c "import sys; sys.stdout.write(raw_input()[::-1])
珀尔:perl -ne 'chomp;print scalar reverse;'
还有更多的可能性反转字符串。也许其中一些可以在您的系统上运行。
答案3
% cat a
1;foo;bar;#@$"é&^l#;baz;x;y;z
2;foo;bar;#¤=é;)o'#;baz;x;y;z
3;foo;bar;#]]'~é{{#;baz;x;y;z
% sed -r 's,^(([^;]+;){3}).*;([^;]+;[^;]+)$,\1\3,' < a
1;foo;bar;y;z
2;foo;bar;y;z
3;foo;bar;y;z
答案4
虽然我个人会使用 awk 或 perl 方法,但这也可以通过(我现在已存档的)Solaris 10 上的 bash 3.2 中的内置命令来完成,无需大量额外的进程:
# unless in a one-off script, save IFS first and restore afterwards
# most simply just put this in parens so it runs in a subshell
IFS=';'; while read -ra a;do N=${#a[*]};
set -- "${a[0]}" "${a[1]}" "${a[2]}" "${a[N-2]}" "${a[N-1]}";
printf %s\\n "${*}";done <in >out