Shell 代码在控制台中有效,但在脚本中无效

Shell code works in console, but not in script

我有一些简单的 shell 代码将在控制台中执行,但不会在脚本中执行。这是我缺乏进步的原因。

我正在尝试隔离触摸屏的 xinput 设备号。这些行在控制台工作:

% NAME="Atmel maXTouch Digitizer"
% DEVICE=`xinput | grep "$NAME" | grep -o "id=[0-9]+" | tr -d id=`
% echo Device found: $DEVICE
Device found: 12

在脚本中,这些确切的行不会产生任何结果:

% touchscreen

Device found:

这一行产生相同的值:

% echo `xinput | grep "Atmel maXTouch Digitizer" | grep -o "id=[0-9]+" | tr -d id=`
12

在脚本中,单行代码也只产生一个空行,这排除了 bad quoting 作为一个可能的原因。

为了弄清楚发生了什么,我分解了代码。在控制台,一切都是金色的:

% NAME="Atmel maXTouch Digitizer"
% LINE=`xinput | grep "$NAME"`
% echo $LINE
⎜   ↳ Atmel Atmel maXTouch Digitizer            id=12   [slave  pointer  (2)]
% PART=`echo $LINE | grep -o "id=[0-9]+"`
% echo $PART
id=12
% DEVICE=`echo $PART | tr -d id=`
% echo Device found: $DEVICE
Device found: 12

在脚本中,它到达第一个 grep,但没有进一步:

% touchscreen
⎜   ↳ Atmel Atmel maXTouch Digitizer            id=12   [slave  pointer  (2)]

Device found:

如果有任何 strange subshell stuff 发生,我希望第一个 grep 也不会工作。

反引号语法的替代方法在控制台仍然有效:

% NAME="Atmel maXTouch Digitizer"
% LINE=$(xinput | grep "$NAME")
% echo $LINE
⎜   ↳ Atmel Atmel maXTouch Digitizer            id=12   [slave  pointer  (2)]
% PART=$(echo $LINE | grep -o "id=[0-9]+")
% echo $PART
id=12
% DEVICE=$(echo $PART | tr -d id=)
% echo Device found: $DEVICE
Device found: 12

...但不在脚本中:

% touchscreen
⎜   ↳ Atmel Atmel maXTouch Digitizer            id=12   [slave  pointer  (2)]

Device found:

与单行代码相同的替代语法也适用于控制台,但不适用于脚本。

我是 运行 Arch Linux 上的 zsh。我已经用 #!/bin/zsh#!/bin/bash 进行了测试,结果相同。我很困惑。

如果您将 grep 与选项 -E 一起使用以启用作为扩展正则表达式的解释,则您正在使用的模式将按预期工作。如果没有 -E+ 必须用 \ 引用:`"grep -o "id=[0-9]+".

所以使用

grep -Eo "id=[0-9]+"

应该可以解决眼前的问题。


它在命令行上工作但在脚本中不起作用的原因很可能是 grep 实际上是使用命令行时 grep -E (可能还有其他一些选项)的别名,但脚本中的实际 grep 命令。您可以通过 运行 type grep.

检查

虽然别名既可以在脚本中使用,也可以在命令行中使用,但它们始终必须在相同的上下文中定义。这可以直接在命令行或脚本中发生,也可以通过在适当的配置文件中进行设置来发生。

对于交互式 shell,这通常发生在 $ZDOTDIR/.zshrc(很可能是 ~/.zshrc)。但是当使用脚本时,只有配置文件 /etc/zshenv$ZDOTDIR/.zshenv 被读取(因为它们对于任何其他 zsh 实例都是如此)。

如果别名仅在 ~/.zshrc 中定义,则它将无法用于脚本。


综上所述,您实际上不需要在此处使用 greptrxinput 可以自行完成您需要的一切:

NAME="Atmel maXTouch Digitizer"
xinput list --id-only $NAME

##If you are not using zsh you may have to quote $NAME (it also works for zsh)
xinput list --id-only "$NAME"

甚至可能不需要,因为 xinput 在大多数情况下可以使用设备名称而不是 id。