【问题标题】:Shell code works in console, but not in scriptShell 代码在控制台中有效,但在脚本中无效
【发布时间】:2015-01-20 04:12:05
【问题描述】:

我有一些简单的 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 对此进行了测试,结果相同。我很困惑。

【问题讨论】:

  • 你能显示实际的脚本吗?除非我们能看到代码,否则很难说是哪里出了问题。
  • 您是否在脚本顶部放置了 shebang (#!/bin/bash)?并且您是否添加了声明 export PATH=/path/to/directory/containing/xinput 以便可以找到 xinput
  • 我认为奇怪的是为什么它可以在 shell 中工作。试试grep -o "id=[0-9]\+"(注意反斜杠),那么它在脚本中有效吗?
  • 为什么不使用 -x 选项运行脚本来调试运行脚本时发生的情况。我会以bash -x myscript.sh 的身份运行脚本。
  • 您对 grep 正则表达式中的转义 + 是正确的,谢谢。 @Adaephon 的详细回答在各个方面都是正确的。

标签: linux bash shell zsh


【解决方案1】:

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

所以使用

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

应该解决眼前的问题。


它在命令行上起作用但在脚本中不起作用的原因很可能是grep 在使用命令行时实际上是别名 vor 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。

【讨论】:

  • 很好的答案,谢谢。你在各个方面都是正确的。 (包括我在尝试变得聪明之前没有阅读 xinput 的手册页。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-08
  • 2015-08-29
  • 1970-01-01
相关资源
最近更新 更多