如何使用tr将一个字符替换为两个字符

52

tr命令能否将一个字符替换为两个字符?

我正在尝试将“〜”替换为“〜\n”,但输出结果没有产生换行符。

$ echo "asdlksad ~ adlkajsd ~ 12345" | tr "~" "~\n"
asdlksad ~ adlkajsd ~ 12345
5个回答

46

不,tr 专门用于将单个字符替换为单个字符(或根据命令行选项删除字符或将连续的单个字符替换为一个字符)。

sed 可能是这个特定工作的最佳工具:

$ echo "asdlksad ~ adlkajsd ~ 12345" | sed 's/~/~\n/g'
asdlksad ~
 adlkajsd ~
 12345

(请注意,这需要sed将反斜杠-n \n序列解释为换行符。GNU sed可以做到这一点,但POSIX除了在正则表达式中指定之外,并没有规定它,而且肯定存在较旧版本的sed不支持该功能。)


7

tr 只能进行一对一的翻译。

以下是使用纯 Bash 的一种方法:

s='"asdlksad ~ adlkajsd ~ 12345'
r=$'~\n'
echo -e "${s//\~/$r}"
asdlksad ~
 adlkajsd ~
 12345

1
这可能比调用 awk 或 sed 等工具更有效率。 - Alex Hall
2
请在此处查看语法的详细解释:https://dev59.com/KWYs5IYBdhLWcg3wBvRp#13210909 - Leo

7
你可以选择使用awk,让FS/OFS变量为你完成任务。
awk -F'~' -v OFS="~\n" '$1=$1' 

使用您的示例进行测试:

kent$ awk -F'~' -v OFS="~\n" '$1=$1' <<< "asdlksad ~ adlkajsd ~ 12345" 
asdlksad ~
 adlkajsd ~
 12345

2
这解决了我的问题,但我不清楚发生了什么,所以我深入挖掘了一下以获得更多的明确信息:"-F" == "输入字段分隔符","-OFS" == "输出字段分隔符"(这里的技巧是“OFS”可以是多个字符),而“<<<”将带引号的字符串作为STDIN传递给awk(在同一个shell中)- 这避免了使用管道时事务在不同的子shell中完成的问题。 - netdesignate

2
抱歉,我不能这样做。 tr 旨在将一个字符转换为另一个字符。
有很多选项,但我会使用 awk
echo "asdlksad ~ adlkajsd ~ 12345" | awk '{gsub(/[~]/, "&\n")};1'

output

asdlksad ~
 adlkajsd ~
 12345

不必使用/[~]/,更短的形式/~/也可以。末尾的;1并非必需的。(或者对于某些古老的操作系统而言是必需的吗?) - Roland Illig

0
echo "asdlksad ~ adlkajsd ~ 12345" | sed 's/~/~|/g' | tr '|' '\n'

--这将完美地工作,因为sed在替换\n时存在问题


如果输入包含其他地方的 |,它就无法工作。 - Roland Illig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接