Sed 没有写入文件
Sed is not writing to file
我只想更改 CSV 文件中的分隔符。
该文件来自外部服务器,因此分隔符是这样的:^A.
name^Atype^Avalue^A
john^Ab^A500
mary^Ac^A400
jack^Ad^A200
我想要这个:
name,type,value
john,b,500
mary,c,400
jack,d,200
我需要将其更改为逗号 (,) 或制表符 (,),但我的 sed 命令尽管输出正确,但并未写入文件。
cat -v CSVFILE | sed -i "s/\^A/,/g"
当我使用上面的行时,它正确地输出了用逗号而不是 ^A 分隔的文件,但它没有写入文件。
我也这样试过:
sed -i "s/\^A/,/g" CSVFILE
也不行...
我做错了什么?
如果您的 sed
支持 -i 选项,您可以像这样使用它:
sed -i.bak -e "s/\^A/,/g" CSVFILE
(这里假定源文件中的分隔符由两个字符 ^ 和 A 组成;如果 ^A 应该指的是 Control-A,那么您将不得不进行相应的调整,例如使用 's/\x01/,/g'
.)
否则,假设您想保留原始文件的副本(例如,以防结果不是您所期望的——见下文),可以使用如下咒语:
mv CSVFILE CSVFILE.bak && sed "s/\^A/,/g" CSVFILE.bak > CSVFILE
正如别处指出的那样,如果源文件分隔符是 Control-A,您也可以使用 tr '[=14=]1' ,
(或 tr '[=15=]1' '\t'
作为制表符)。
需要注意的是,源文件中的定界符可能恰好被使用,因为逗号可能出现在分隔符分隔的“值”中。如果这是可能的,那么将需要一种不同的方法。 (参见 https://www.rfc-editor.org/rfc/rfc4180)
如果 运行 在 OS X 下:
添加扩展名到-i
以写入新文件:
sed -i.bak "s/^A/,/g" CSVFILE
或写到位:
sed -i '' "s/^A/,/g" CSVFILE
您也可以使用 cat 输出到文件,但在您的 sed 上没有 -i
命令:
cat -v CSVFILE | sed "s/^A/,/g" > ouput
确保你这样写 ^A :
Ctrl+V+Ctrl+A
这是 tr
创建的目的:
tr '<control-A>' ',' < file > tmp && mv tmp file
显然用文字控件-A替换<control-A>
。
文字 ^A
(两个字符,^
和A
)是如何cat -v
可视化控制字符0x1
(ASCII码1
,命名为SOH
(标题开始))。 ^A
是一个例子caret notation到表示unprintable ASCII字符:
^A
代表键盘组合 Control-A,当其前面有通用转义序列 Control-V,是您可以在终端中创建 actual 控制字符的方法;换句话说,
Control-VControl-A 将插入一个实际的 0x1
字符。
顺带一提,caret notation(^<letter>
)的逻辑是:字母对应所表示的控制字符的ASCII值;例如,A
对应0x1
,D
对应0x4
(^D
,EOT
)。
换句话说:您将 0x40
添加到控制字符的 ASCII 值,以获取其以脱字符号表示的字母表示的 ASCII 值。
^@
表示NUL
(0x0
个字符)和^?
表示DEL
(0x7f
)与这种写法一致,因为@
具有 ASCII 值 0x40
(即,它刚好在 ASCII table 中的 A
(0x41
) 之前)并且 0x40 + 0x7f
被限制为 7 位(bit-ANDed 与最大 ASCII 值 0x7f
) 产生 0x3f
,这是 ?
.
的 ASCII 值
要检查给定文件的 ASCII 值 外来控制字符,您可以将其通过管道传输到 od -c
,将 0x1
表示为(八进制)001
.
这意味着,将文件直接sed
传递时,您不能使用脱字符号,而必须使用您的 s
调用中的 实际控制字符 。
- 请注意,当您使用 Control-VControl-A 创建一个 actual
0x1
字符,它也会 出现 插入符号 - 如 ^A
- 但在那种情况下它只是 终端的真控角色观想;虽然它可能看起来像两个主要table字符^
和A
,但它不是。纯粹从视觉上看不出区别 - 这就是为什么 使用转义序列或 ANSI C-quoted 字符串来表示控制字符是更好的选择 - 见下文。
假设您的 shell 是 bash
、ksh
或 zsh
,使用 [=181 的更好选择=]Control-A是使用ANSI C-quoted string生成0x1
字符:$''
- 然而,正如 Lars Fischer 在对该问题的评论中指出的那样,GNU
sed
也识别 \x01
的转义序列 0x1
.
因此,您的命令应该是:
sed -i 's/\x01/,/g' CSVFILE # \x01 only recognized by GNU sed
或者,使用 ANSI C-quoted 字符串:
sed -i $'s//,/g' CSVFILE
注:虽然这种形式原则上可以与BSD/OSX一起使用sed
,-i
语法略有不同:您必须使用 sed -i '' $'s//,/g' CSVFILE
为您的任务使用 sed
的唯一原因是利用 in-place 更新 (-i
);否则,tr
是更好的选择 - 请参阅 Ed Morton's answer。
我只想更改 CSV 文件中的分隔符。 该文件来自外部服务器,因此分隔符是这样的:^A.
name^Atype^Avalue^A
john^Ab^A500
mary^Ac^A400
jack^Ad^A200
我想要这个:
name,type,value
john,b,500
mary,c,400
jack,d,200
我需要将其更改为逗号 (,) 或制表符 (,),但我的 sed 命令尽管输出正确,但并未写入文件。
cat -v CSVFILE | sed -i "s/\^A/,/g"
当我使用上面的行时,它正确地输出了用逗号而不是 ^A 分隔的文件,但它没有写入文件。
我也这样试过:
sed -i "s/\^A/,/g" CSVFILE
也不行... 我做错了什么?
如果您的 sed
支持 -i 选项,您可以像这样使用它:
sed -i.bak -e "s/\^A/,/g" CSVFILE
(这里假定源文件中的分隔符由两个字符 ^ 和 A 组成;如果 ^A 应该指的是 Control-A,那么您将不得不进行相应的调整,例如使用 's/\x01/,/g'
.)
否则,假设您想保留原始文件的副本(例如,以防结果不是您所期望的——见下文),可以使用如下咒语:
mv CSVFILE CSVFILE.bak && sed "s/\^A/,/g" CSVFILE.bak > CSVFILE
正如别处指出的那样,如果源文件分隔符是 Control-A,您也可以使用 tr '[=14=]1' ,
(或 tr '[=15=]1' '\t'
作为制表符)。
需要注意的是,源文件中的定界符可能恰好被使用,因为逗号可能出现在分隔符分隔的“值”中。如果这是可能的,那么将需要一种不同的方法。 (参见 https://www.rfc-editor.org/rfc/rfc4180)
如果 运行 在 OS X 下:
添加扩展名到
-i
以写入新文件:sed -i.bak "s/^A/,/g" CSVFILE
或写到位:
sed -i '' "s/^A/,/g" CSVFILE
您也可以使用 cat 输出到文件,但在您的 sed 上没有
-i
命令:cat -v CSVFILE | sed "s/^A/,/g" > ouput
确保你这样写 ^A :
Ctrl+V+Ctrl+A
这是 tr
创建的目的:
tr '<control-A>' ',' < file > tmp && mv tmp file
显然用文字控件-A替换<control-A>
。
文字
^A
(两个字符,^
和A
)是如何cat -v
可视化控制字符0x1
(ASCII码1
,命名为SOH
(标题开始))。^A
是一个例子caret notation到表示unprintable ASCII字符:^A
代表键盘组合 Control-A,当其前面有通用转义序列 Control-V,是您可以在终端中创建 actual 控制字符的方法;换句话说,
Control-VControl-A 将插入一个实际的0x1
字符。顺带一提,caret notation(
^<letter>
)的逻辑是:字母对应所表示的控制字符的ASCII值;例如,A
对应0x1
,D
对应0x4
(^D
,EOT
)。
换句话说:您将0x40
添加到控制字符的 ASCII 值,以获取其以脱字符号表示的字母表示的 ASCII 值。
^@
表示NUL
(0x0
个字符)和^?
表示DEL
(0x7f
)与这种写法一致,因为@
具有 ASCII 值0x40
(即,它刚好在 ASCII table 中的A
(0x41
) 之前)并且0x40 + 0x7f
被限制为 7 位(bit-ANDed 与最大 ASCII 值0x7f
) 产生0x3f
,这是?
. 的 ASCII 值
要检查给定文件的 ASCII 值 外来控制字符,您可以将其通过管道传输到
od -c
,将0x1
表示为(八进制)001
.
这意味着,将文件直接
sed
传递时,您不能使用脱字符号,而必须使用您的s
调用中的 实际控制字符 。- 请注意,当您使用 Control-VControl-A 创建一个 actual
0x1
字符,它也会 出现 插入符号 - 如^A
- 但在那种情况下它只是 终端的真控角色观想;虽然它可能看起来像两个主要table字符^
和A
,但它不是。纯粹从视觉上看不出区别 - 这就是为什么 使用转义序列或 ANSI C-quoted 字符串来表示控制字符是更好的选择 - 见下文。
- 请注意,当您使用 Control-VControl-A 创建一个 actual
假设您的 shell 是
bash
、ksh
或zsh
,使用 [=181 的更好选择=]Control-A是使用ANSI C-quoted string生成0x1
字符:$''
- 然而,正如 Lars Fischer 在对该问题的评论中指出的那样,GNU
sed
也识别\x01
的转义序列0x1
.
- 然而,正如 Lars Fischer 在对该问题的评论中指出的那样,GNU
因此,您的命令应该是:
sed -i 's/\x01/,/g' CSVFILE # \x01 only recognized by GNU sed
或者,使用 ANSI C-quoted 字符串:
sed -i $'s//,/g' CSVFILE
注:虽然这种形式原则上可以与BSD/OSX一起使用sed
,-i
语法略有不同:您必须使用 sed -i '' $'s//,/g' CSVFILE
为您的任务使用 sed
的唯一原因是利用 in-place 更新 (-i
);否则,tr
是更好的选择 - 请参阅 Ed Morton's answer。