读取带有特殊字符的字符串并在`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
范围的替换
我尝试了以下
tr
1
read -r A
tr $A A-Z
tr
2
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】:
对于tr
和sed
实用程序,可以使用\
转义特殊字符。程序tr
和sed
有不同的特殊字符集和解析规则。但是,对于两个程序来说,只转义 [
-
和 \
似乎就足够了。
IFS= read -r a;
a=$(sed 's/[[\-]/\\&/g' <<<"$a")
tr "$a" 'A-Z'
# or
sed "y/$a/ABCDEFGHIJKLMNOPQRSTUVWXYZ/"
使用 shellcheck.net 检查您的脚本。研究 shell 中的引用以及何时使用它。研究如何调试脚本和关于set -x
选项。请参阅 sed
和 tr
文档 - 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】:
tr
和sed
都是过滤器;它们从标准输入中读取一行或多行,执行转换(在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 中使用特殊字符传递我的密码
使用 std::wifstream 读取带有特殊字符的 unicode 文件