读取带有特殊字符的字符串并在`tr`和`sed`中使用它[关闭]

Posted

技术标签:

【中文标题】读取带有特殊字符的字符串并在`tr`和`sed`中使用它[关闭]【英文标题】:Read a string with special characters and use it in `tr` and `sed` [closed] 【发布时间】:2021-09-30 13:42:49 【问题描述】:

我有以下字符串

$A%^]I"S-)|>J&`_@;!UVPOSM\
IV&|M

这包含特殊字符,因此Bash 无法正确解释,除非被引用

第一个字符串只是A-Z范围的替换

我尝试了以下

tr1

read -r A
tr $A A-Z

tr2

read -r A
tr "$A" A-Z

使用sed

read -r A
sed "y/$A/ABCDEFGHIJKLMNOPQRSTUVWXYZ/"
read -r A
sed 'y/'$A'/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'
read -r A
sed 'y/'$A'/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'

他们都没有工作。此外,在read 中使用选项-ps 也不起作用。

tr 的错误是

tr: range-endpoints of 'S-)' are in reverse collating sequence order

sed 出错

sed: -e expression #1, char 56: unterminated `y' command

将第一个字符串翻译成 A-Z 时的输出将给出“FUNKY”

如何解决?

【问题讨论】:

read -r A 会读一行。你有两条线。 'y/'$A'/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' 我不明白 - 你想替换什么。在什么地方? 是的。它将自动将第二行中的命令应用于下一个输入。所以,我不需要阅读第二行 不,它不会,read 读取一行。它是什么”? use it in tr and sed如何你想“使用”这个字符串? How to resolve this? tr 错误是正确的 - 字符串是 tr 的无效参数。至于sed,换行换​​成\n “它”指的是在线IDE 所有的 STDIN 将一次性提供。因此,在线 IDE 会自动将该命令应用于所有剩余的输入行 【参考方案1】:

对于trsed 实用程序,可以使用\ 转义特殊字符。程序trsed 有不同的特殊字符集和解析规则。但是,对于两个程序来说,只转义 [ -\ 似乎就足够了。

IFS= read -r a;
a=$(sed 's/[[\-]/\\&/g' <<<"$a")
tr "$a" 'A-Z'
# or
sed "y/$a/ABCDEFGHIJKLMNOPQRSTUVWXYZ/"

使用 shellcheck.net 检查您的脚本。研究 shell 中的引用以及何时使用它。研究如何调试脚本和关于set -x 选项。请参阅 sedtr 文档 - https://pubs.opengroup.org/onlinepubs/009695299/utilities/tr.html 和 https://www.gnu.org/software/sed/manual/sed.html 。更喜欢使用小写的变量名。您也可能对https://mywiki.wooledge.org/BashFAQ/001 和https://en.wikipedia.org/wiki/Here_document#Here_strings 感兴趣。

我认为最好的完整证明方法可能是转换第一行并转换为八进制 \NNN 数字,然后传递给 tr。像这样:

IFS= read -r a;
a=$(printf "%s" "$a" | od -An -b | tr -d ' \n' | sed 's/.../\\&/g');
tr "$a" 'A-Z';

【讨论】:

我不认为 tr 需要 [ 被转义;相反,sed 中的y 命令不将- 识别为范围运算符。 (这通常被视为一个缺点,但在这里很适合我们。)【参考方案2】:

trsed 都是过滤器;它们从标准输入中读取一行或多行,执行转换(在sed 中可以是一个非常复杂的脚本,带有条件分支和循环),并将结果打印到标准输出。

sed 中的y 命令与tr 非常相似;它们都接受两个字符列表,其中第一个列表中的第 n 个字符将映射到第二个列表中的第 n 个字符。

tr 有一个附加功能,您可以缩写相邻字符的列表;因此tr A-Za-z N-ZA-Mn-za-m 实现了熟悉的rot13 算法。这解释了为什么当您尝试传入带有破折号的字符串时会出错 - 它被解释为范围运算符,但被视为无效,因为范围的开头具有比其结尾更高的字符代码。

sed 错误的出现是因为反斜杠被解释为转义最后的分隔符; \/ 是在替换或替换字符串中放置文字斜线的方式。

如果我正确理解您的问题,您想将 A-Z 映射到输入的第一行,并将第二行作为此转换的输入吗?

#!/bin/bash
exec <"$1"
IFS='' read -r A
sed "y/$A//\\/\\\\/ABCDEFGHIJKLMNOPQRSTUVWXYZ/"

exec 告诉 Bash 从指定文件中读取标准输入;您可以将文件名作为参数传递给该脚本。字符串替换 $A//pattern/replacement 负责将变量值中的任何文字反斜杠加倍。

tr 想出类似的东西并非不可能。主要挑战是您必须将破折号放在首位或最后,并相应地重新排序输出映射。一些tr 实现可能允许您使用--- 指定一个字符范围,其中中间破折号是范围运算符,另外两个是范围的开始和结束字符。

【讨论】:

以上是关于读取带有特殊字符的字符串并在`tr`和`sed`中使用它[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

从 sql server 读取数据并在 PySpark 中使用特殊字符传递我的密码

在 Apache Web 服务器中读取带有特殊字符的图像

如何在python中读取带有特殊字符的文本文件

使用 std::wifstream 读取带有特殊字符的 unicode 文件

云计算学习Days2--cat head tail sort uniq wc cut sed grep awk tr

如何从文件中读取特殊字符?