我正在处理一个csv文件,所以假设我有这样一列:
5, 10,在11;20;& lt; 14
我想要的输出是:
5, 10, 12, 20; 13
所以我想在bash语言中对那些大于(>)符号的值加上+1,对那些小于(<)符号的值减去1。我用sed尝试了一些奇怪的东西,但考虑到它将这些更改解释为字符串,它没有成功。
有什么建议吗?
使用awk
(使用GNUawk
测试):
$ awk -F; -v OFS=; '
{
for(i = 1; i <= NF; i++) {
if($i ~ /^<[[:digit:]]+$/) {
sub(/^</,"",$i)
$i--
}
else if($i ~ /^>[[:digit:]]+$/) {
sub(/^>/,"",$i)
$i++
}
}
} 1' <<< "5;10;>11;20;<14"
5;10;12;20;13
警告:当且仅当您信任您的输入文件并且您100%确定它不包含恶意字段(请参阅最后注释)时使用以下字段。
对于GNUsed
(假设您的shell是bash
),有点短,但也有点难以理解(与sed
一样):
$ sed -E '
s/<([[:digit:]]+)/$((1-1))/g
s/>([[:digit:]]+)/$((1+1))/g
s/.*/printf "%sn" "&"/e
' <<< "5;10;>11;20;<14"
5;10;12;20;13
也就是说(其中N
是一串数字),将所有<N
替换为$((N-1))
,将所有>N
替换为$((N+1))
,将结果字符串S
替换为printf "%sn" "S"
,用bash
执行并替换为输出(这就是替换命令的e
修饰符所做的)。在您的示例中,输入字符串依次变为:
5;10;>11;20;$((14-1))
5;10;$((11+1));20;$((14-1))
printf "%sn" "5;10;$((11+1));20;$((14-1))"
5;10;12;20;13
这里有一个严重的安全问题的原因是,如果你的一个字段是,例如,$(rm -rf ~/*)
,它会简单地递归删除你的整个主目录…因此,如果您不控制输入,请选择awk
版本。
5;10;>11;20;<14
|
{m,g}awk '
BEGIN {
_*=(OFS= "") (__-=_^= FS ="("(
___="3117")"|"(____="1624")")+"
} {
gsub(";[<>][0-9]+",____ "&" ___)
gsub(____ ";[<>]", "&" ___)
NF
for(_+=(_^=($_=$_)<"")+_;_<=NF;_++) {
if ($_~"^[0-9]+$") {
$_+=__^($(_+__)~"[<]$")
}
} print $(_=_<_) }'
=
5;10;>12;20;<13