【发布时间】:2021-12-31 01:06:48
【问题描述】:
我正在编写一个 POSIX shell 函数,它将其参数打印为 TSV 记录。
每个参数都使用以下规则进行转义:
-
\n换行 -
\t标签页 -
\r用于回车 -
\\用于反斜杠
函数如下:
#!/bin/sh
tsv_print() {
rec=
for str in "$@"
do
esc=
i=${#str}
until [ $i -eq 0 ]
do
end="${str#?}"
chr="${str%"$end"}"
case $chr in
"$__TAB__") chr='\t' ;;
"$__LF__") chr='\n' ;;
"$__CR__") chr='\r' ;;
\\) chr='\\' ;;
esac
esc="$esc$chr"
str="${end}"
i=$((i-1))
done
rec="$rec${rec:+"$__TAB__"}$esc"
done
# echo "$rec"
printf '%s\n' "$rec"
}
在代码中读起来很痛苦——预先存储的字符如下:
__TAB__=$(printf '\t')
__CR__=$(printf '\r')
__LF__="
"
我想知道:
-
为什么我的代码根本不转义字符?edit: 正如@GordonDavisson 指出的那样,
echo是 罪魁祸首!!使用printf似乎是唯一可移植的方式,但代价是可能的分叉。 -
有更好的、符合 POSIX 的方法吗?
awk和sed似乎不适合这份工作...... -
你会怎么做?
编辑:正如@KamilCuk 在他的answer 中发布的那样,
printf '%b'就足够了; TSV 记录具有正确的格式。
后记
最后,不需要该函数,因为输入不包含任何要转义的字符。也就是说,输入格式的转换并不是那么简单。这是一个STAR File,每行有不同的列数(将行数限制为最多 80 个字符)并包含带引号的字符串...
输入:
...
loop_
_refl_0201 _refl_0012 _refl_2003 _refl_1600 _refl_1304 _refl_1305 _refl_1800
_refl_1801 _refl_1802 _refl_1803 _refl_1804 _refl_1805 _refl_1806 _refl_1701
_refl_1700 _refl_1202
'0 0 6' .147364 Z000020c1 .41 1 78.45 3.501 35.2221 -35.2221 0 -1.6055 -3.0963
-36.7288 -5.0964 39.3109 5.909983 '0 0 12' .294551 Z000010c1 .9 1 48.44 2.3805
39.910008 39.9101 .268379-04 1.75598 3.09745 41.6656 3.09809 47.8384 0 .939517
...
输出(分隔符是制表符):
_refl_0201 _refl_0012 _refl_2003 _refl_1600 _refl_1304 _refl_1305 _refl_1800 _refl_1801 _refl_1802 _refl_1803 _refl_1804 _refl_1805 _refl_1806 _refl_1701 _refl_1700 _refl_1202
'0 0 8' .147364 Z000020c1 .41 1 78.45 3.501 35.2221 -35.2221 0 -1.6055 -3.0963 -36.7288 -5.0964 39.3109 5.909983
'0 0 14' .294551 Z000010c1 .9 1 48.44 2.3805 39.910008 39.9101 .268379-04 1.75598 3.09745 41.6656 3.09809 47.8384 0.939517
...
【问题讨论】:
-
我认为您的
echo命令可能正在解释转义序列。请改用printf '%s\n' "$rec"。 -
你写超级POSIX兼容脚本有什么具体原因吗?
-
我理解您的帖子的方式是您的数据嵌入了转义字符,您试图将其转换为“真实”“格式”(制表符等)字符?如果是,那么,这就是疯狂之路。希望一关。不要接受格式错误的提要!否则编辑您的 Q 以显示准确的示例输入文本和所需的输出。祝你好运。
-
$(...)将始终去除尾随的换行符。但是你不需要它来设置__LF__;你可以简单地输入__LF__=",回车,然后用"完成命令。__TAB__或__CR__不需要这样的技巧:单独使用__TAB__=$(printf '\t')就足够了,__CR__也是如此。 -
@KamilCuk 目标系统是旧的 SGI IRIX,我不确定它的 bourne shell 的功能。我的一位退休同事让我在上面运行他的一个 super 程序(当时确实是这样^^),所以我必须将数据复制到外部 SCSI 磁盘(连同使用我的脚本),转到计算机,使用数据运行第一个程序,将其输出转换为 TSV,然后运行目标程序。我的同事告诉我,我必须将伪 CSV(没有转义,但包含标签)转换为有效的 TSV。他自己当时是手动做的……