duvel71
duvel71

Reputation: 23

Shell code works in console, but not in script

I have some simple shell code that will execute in the console, but not in a script. Here's an account of my lack of progress.

I'm trying to isolate the xinput device number of my touch screen. These lines work at the console:

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

In a script those exact lines produce nothing:

% touchscreen

Device found:

This one-liner produces the same value:

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

In a script, the one-liner also produces only a blank line, which eliminates bad quoting as a possible cause.

To clarify what's going on, I broke the code up. At the console, all is golden:

% 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

In a script it gets as far as the first grep, but no further:

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

Device found:

If there was any strange subshell stuff going on, I'd expect the first grep not to work either.

An alternative to the backtick syntax still works at the console:

% 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

...but not in a script:

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

Device found:

The same alternative syntax with the one-liner also works at the console, but not in a script.

I'm running zsh on Arch Linux. I have tested this with both #!/bin/zsh and #!/bin/bash, with identical results. I'm flummoxed.

Upvotes: 2

Views: 996

Answers (1)

Adaephon
Adaephon

Reputation: 18419

The pattern you are using only works as expected if you use grep with the option -E to enable interpretation as an extended regular expression. Without -E the + has to be quoted with a \: `"grep -o "id=[0-9]+".

So using

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

should solve the immediate problem.


The reason it works on the command line but not in a script is most likely that grep is actually an alias vor grep -E (and maybe some other options) when using the commandline but the actual grep command in the script. You can check this by running type grep.

While aliases can be used in scripts just as well as on the command line, they always have to be defined in the same context. This can happen either directly on the command line or in the script or by setting it in the appropriate configuration files.

For interactive shells this usually happens in $ZDOTDIR/.zshrc (most likely ~/.zshrc). But when using scripts only the configuration files /etc/zshenv and $ZDOTDIR/.zshenv are read (as they are for any other zsh instance for that matter).

If the alias is defined just in ~/.zshrc it will not be available for scripts.


That all being said, you do not actually need to use grep or tr here. xinput can do all you need on its own:

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"

And even that is probably not needed, as xinput can use the name of the device instead of the id in most situations.

Upvotes: 1

Related Questions