TMOUT innerhalb der Skriptdatei verhält sich beim Auswahlbefehl falsch. Wie kann ich das beheben?

TMOUT innerhalb der Skriptdatei verhält sich beim Auswahlbefehl falsch. Wie kann ich das beheben?

AKTUALISIEREN- sieht so aus, als wäre das etwas Eigenartiges bei Bash 4.3.42, da es mit 4.3.46 einwandfrei funktioniert. Ich hinterlasse diesen Beitrag für diejenigen, die in Zukunft auf dasselbe Problem stoßen.

Wenn ich diesen Befehl in der Bash-Befehlszeile ausführe, funktioniert er ordnungsgemäß:

% (TMOUT=3; s="no selection"; select s in a b c ; do break ; done; echo $s)
1) a
2) b
3) c
#?
no selection
% _

Ergebnis: zeigtkeine Auswahlund kehrt zur Befehlszeile zurück.

Wenn ich jedoch ein Skript platziere und es ausführe, werde ich wiederholt zur Auswahl aufgefordert.

% cat a.sh
#!/bin/bash
(TMOUT=3; s="no selection"; select s in a b c ; do break ; done; echo $s)

% ./a.sh

Ergebnis:

1) a
2) b
3) c
#? 1) a
2) b
3) c
#? 1) a
2) b
3) c
#? ^C
% _

Warum ist das so? Meine Hauptfrage ist -wie lässt sich das in einem Skript zum Laufen bringen?!

AKTUALISIERT

% bash --version
GNU bash, version 4.3.42(1)-release (x86_64-unknown-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.

% uname
Linux lx1 2.6.32-642.6.2.el6.x86_64 #1 SMP Mon Oct 24 10:22:33 EDT 2016 x86_64 x86_64 x86_64 GNU/Linux

Antwort1

Aus dem Handbuch:

TMOUT Wenn TMOUT auf einen Wert größer als Null gesetzt ist, wird es als Standard-Timeout für das integrierte Lese-Befehlselement behandelt. Der Select-Befehl wird beendet, wenn die Eingabe nach TMOUT Sekunden nicht eintrifft, wenn die Eingabe von einem Terminal kommt. In einer interaktiven Shell wird der Wert als Anzahl der Sekunden interpretiert, die nach der Ausgabe der primären Eingabeaufforderung auf eine Eingabe gewartet werden soll. Bash wird beendet, wenn diese Anzahl von Sekunden gewartet wird und keine Eingabe eintrifft.

Der erste Fall ist also auf die interaktive Shell zurückzuführen.

$ ps -aef|grep bash; echo "before"; (TMOUT=3; s="no selection"; ps -aef|grep bash; select s in a b c ; do break ; done; echo $s;ps -aef|grep bash);echo "after";ps -aef|grep bash
asktyagi    4926 23767  0 09:40 pts/0    00:00:00 grep --color=auto bash
asktyagi   23767 23741  0 09:03 pts/0    00:00:00 -bash
**before**
asktyagi    4927 23767  0 09:40 pts/0    00:00:00 -bash
asktyagi    4929  4927  0 09:40 pts/0    00:00:00 grep --color=auto bash
asktyagi   23767 23741  0 09:03 pts/0    00:00:00 -bash
1) a
2) b
3) c
#?
no selection
asktyagi    4927 23767  0 09:40 pts/0    00:00:00 -bash
asktyagi    4931  4927  0 09:40 pts/0    00:00:00 grep --color=auto bash
asktyagi   23767 23741  0 09:03 pts/0    00:00:00 -bash
**after**
asktyagi    4933 23767  0 09:40 pts/0    00:00:00 grep --color=auto bash
asktyagi   23767 23741  0 09:03 pts/0    00:00:00 -bash

Jetzt mit Skript

$ cat a.sh
#!/bin/bash
(TMOUT=3; s="no selection"; select s in a b c ; do break ; done; echo $s)
ps -aef|grep bash

$ sh a.sh
1) a
2) b
3) c
#?
no selection
asktyagi    5201  5188  0 09:41 pts/0    00:00:00 grep bash
asktyagi   23767 23741  0 09:03 pts/0    00:00:00 -bash

Antwort2

Verwenden Sie den timeoutBefehl. Dieses Beispiel könnte verbessert werden, aber es macht den Punkt deutlich. Verwenden Sie zuerst den in bash integrierten trapBefehl, um beim Beenden etwas auszuführen, und führen Sie dann Ihre Schleife aus. Sie läuft wie folgt ab:

#] timeout 3s sh -c 'trap "echo no selection" EXIT; select s in a b c ; do break ; done; '
1) a
2) b
3) c
#? <waits 3 seconds>no selection

Antwort3

Letztendlich habe ich also meine eigene Auswahl geschrieben, die in einem Skript verwendet werden kann.

# $1 timeout
# rest - selection
function select_ {
  t=$1
  shift
  arr=($*)
  i=1
  for a in $*; do
    echo "$i) $a" >$(tty)
    ((i++))
  done
  echo "TIMEOUT: In ${t} seconds ${arr[0]} will be automatically selected." >$(tty)
  printf "#? " >$(tty)
  read -t $t x
  [ "$x" == "" ] && {
     x=1
     echo "$x" >$(tty)
  }
  ((x=x+0))
  [ "$x" -ge 1 -a "$x" -le ${#arr[@]} ] && {
    ((x--))
    echo ${arr[$x]}
  }
}

So verwenden Sie es:

select_ 10 a b c

Beispiel:

$ ./x.sh
1) a
2) b
3) c
TIMEOUT: In 10 seconds a will be automatically selected.
#? 2
b

$ ./x.sh
1) a
2) b
3) c
TIMEOUT: In 10 seconds a will be automatically selected.
#? 1
a

verwandte Informationen