变量打印相同的值但实际上值是不同的

变量打印相同的值但实际上值是不同的

使用以下语法来捕获 xml 文件中的单词 我还使用 xargs 来删除任何空格

var=` find /tmp -name '*.xml' -exec sed -n 's/<Name>\([^<]*\)<\/Name>/\1/p' {} +  |  xargs `

echo $var
TOPIC

到目前为止似乎还可以

但 printf 显示其他内容

printf "%q\n" "$var"
$'TOPIC\r'

让我们深入研究

[[ TOPIC == $var ]] && echo they are equal

没有打印“他们是平等的

但是当我们打印 $var 时我们得到

echo $var
TOPIC

所以事情看起来清楚之后

最大的问题是:

如何从变量中删除多余的字符( $ , \r ) -

$'TOPIC\r'

答案1

这是您的实现给出的用于表示该变量内容的$'TOPIC\r'视觉表示。printf它使用 ksh93 的$'...'引用形式(现在也受 和一些其他 shell 支持zshbash来为您提供该表示形式。在这些 shell 中,var=$'TOPIC\r'将创建一个$var具有相同内容的变量。在这种引用形式中,\r代表回车符。

这是一个字符,当发送到终端时,终端会将光标移动到行首。它是终端的控制字符,不是具有与其关联的字形的普通字符。

printf 'ABC\rX\n'

( printf,在其格式参数也被识别\r为 CR 字符的含义)显示为:

XBC

如果你写:

printf 'ABC\rX\n' | pv -qL3

放慢速度,你可以看看会发生什么。

要删除它,使用类似 ksh93 的 shell(ksh93、zsh、bash 或 mksh),您可以执行以下操作:

var=${var//$'\r'}

\r也被归类为[:space:]字符。因此,您还可以使用以下方法删除所有空格字符:

var=${var//[[:space:]]}

要仅删除 CR 字符(变量末尾的字符):

var=${var%$'\r'}

(应该可以移植到更多的 shell)。

POSIXly(就像在可移植sh脚本中一样),你可以这样做:

var=$(printf %s "$var" | tr -d '\r')

但请注意,它还会删除\n变量内容末尾的换行符(又名换行符,又名换行符,又名 LF 又名)。

顺便说一句,[[ TOPIC = $var ]]kshzsh 和 bash 也支持 ism)是一个模式匹配运算符,而不是相等测试运算符(除了zsh不模拟 ksh/bash 时),您需要[[ TOPIC = "$var" ]]测试相等性,var=*; [[ TOPIC = $var ]]将返回真的例如(并且var='[x]'; [[ $var = $var ]]会返回错误的)。

还请记住echo不能用于输出任意数据参数扩展通常应该被引用

$ var=$'TOPIC\r'
$ printf '%s\n' "$var" # zsh (my shell) builtin
TOPIC
$ printf '%q\n' "$var"
TOPIC$'\r'
$ /usr/bin/printf '%q\n' "$var" # GNU printf
'TOPIC'$'\r'
$ (export var; bash -c 'printf "%q\n" "$var"') # bash builtin
$'TOPIC\r'
$ (export var; ksh93 -c 'printf "%q\n" "$var"') # ksh93 builtin
$'TOPIC\r'
$ (export var; dash -c 'printf "%q\n" "$var"')
dash: 1: printf: %q: invalid directive

%q不是标准printf指令,并非所有实现都支持它,并且行为因实现而异。sed -n l是一种获取字符串的明确视觉表示的可移植/标准方法(尽管输出在实现之间也有所不同):

$ printf '%s\n' "$var" | sed -n l
TOPIC\r$

$显示行尾(对于具有尾随空格的行很有用)。

$ var=${var//$'\r'}
$ printf '%s\n' "$var" | sed -n l
TOPIC$

答案2

is符号\r继承自 C,表示回车符。您的文件很可能具有 DOS/Windows 风格的 CRLF 行结尾。sed并将xargsCR 视为另一个字符,它就会被传递。尽管同一行上<Name>...</Name>标记之外的任何其他内容也会被该 sed 传递。

$ echo 'foo <Name>bar</Name><Num>123</Num>' | sed 's/<Name>\([^<]*\)<\/Name>/\1/'
foo bar<Num>123</Num>

如果您从这样的 XML 文件中选择字段,您可能希望sed同时删除该行周围的任何其他内容:

$ echo 'foo <Name>bar</Name><Num>123</Num>' | sed 's/.*<Name>\([^<]*\)<\/Name>.*/\1/'
bar

这也应该消除最后的任何 CR,因为它们与.*.

相关内容