shell 脚本未将空格用作参数分隔符(有人可以解释一下这个小文件差异吗?)

shell 脚本未将空格用作参数分隔符(有人可以解释一下这个小文件差异吗?)

简短版本(TL;DR)

我有 2 个小的单行文件,似乎完全相同的 :

$ cat f1 f2
./cconv.sh 100 EUR USD
./cconv.sh 100 EUR USD

但它们不是,大小有 1 个字节的差异:

$ ls -l f1 f2
(...) 24 oct.  30 16:19 f1
(...) 23 oct.  30 16:19 f2

$ diff f1 f2
1c1
< ./cconv.sh 100 EUR USD
---
> ./cconv.sh 100 EUR USD

我曾经dhex计算过十六进制的差异。看起来 :

  • f1结束于c2 a0 55 53 44 0a
  • f2结束于20 55 53 44 0a

有人知道这里发生了什么事吗?有什么区别,更重要的是,它从哪里来?以下是链接包含这两个文件的 zip 文件以及dhex结果的屏幕截图。

长版(附加说明)

这两个文件是我的~/.bash_history file.

我注意到我的贝壳有一种非常奇怪的行为。采用以下非常基本的脚本:

#!/bin/sh
echo $#
echo "$1"
echo "$2"
echo "$3"
exit 0

在某些情况下(但哪些???),它不将空格作为参数分隔符:

$ ./cconv.sh 100 EUR USD
2
100
EUR USD

但有时它会像预期的那样工作:

$ ./cconv.sh 100 EUR USD
3
100
EUR
USD

这让我发疯!我花了几个小时试图弄清楚发生了什么事。以下是我尝试缩小范围的一些测试:

  • 我使用装有 Debian 11、Gnome 3.38 的笔记本电脑。但我碰巧也有一个具有完全相同操作系统(D11、G3.38)的虚拟机,并且在虚拟机中一切正常。很明显,我一定对我的裸机笔记本电脑做了什么,它才会出现异常行为。但什么???
  • 我注意到该问题仅发生在图形会话中。如果我打开一个 tty (Ctrl+Alt+Fn),效果很好
  • 我怀疑我的终端模拟器。但不同模拟器中的行为是相同的(我尝试了 Gnome Terminal、Terminator 和 Konsole,结果相同)
  • 我怀疑是外壳。但 Bash 或 Dash 的行为是相同的
  • 我禁用了所有我能想到的自定义:
    • 我暂时删除了/etc/bashrc, /etc/profile,/etc/inputrc/etc/rc.local
    • 我暂时删除了~/.bashrc~/.profile并且~/.inputrc
    • 我禁用了所有 Gnome Shell 的扩展
  • 我什至怀疑键盘的问题,就插了一个USB键盘。相同的结果。

我真的很困惑,不知道发生了什么。我终于注意到 中的 2 个命令之间存在细微差别~/.bash_history:一个来自我的 Gnome 会话,另一个来自我的 tty 会话。显然是有区别的,但是到底是什么,以及可能的原因是什么?

答案1

c2 a0是 UTF-8 编码不间断空格字符。它通常看起来像一个常规空格,但 shell 不会将其识别为空白。

在一些键盘映射中,类似AltGr+SpaceOption+ 的东西Space会产生不间断的空格。如果您的键盘映射在AltGr或后面还有管道字符Option,这会很有趣,这样可以更轻松地键入|<nbsp>而不是|<sp>,从而给出如下错误:

$ echo foo | grep .
bash:  grep: command not found

(我认为 SE 将 nbsp 折叠到常规空间,因此如果从此处复制粘贴,您可能不会收到错误。)

如果您从其他工具复制并粘贴参数,您可能会从那里得到奇怪的格式,但这取决于程序。

shell中处理nbsp字符一些不产生角色的解决方案。

相关内容