How can you prevent ANSI escape sequences from being written to a debug file in a Bash script? #3792
-
In the script below, I attempt to collect everything into a debug file when #!/usr/bin/env bash
set -o allexport -o errexit -o nounset -o pipefail
unset FZF_DEFAULT_OPTS FZF_DEFAULT_COMMAND
DEBUG_MODE=${DEBUG_MODE:-0}
if ((DEBUG_MODE)); then
debug_file=$(mktemp)
trap 'echo "[DEBUG] $debug_file"' EXIT
exec 2> >(tee -a "$debug_file")
# Customized trace prompt
PS4='+ $(date +%Y-%m-%d:%H:%M:%S) [${BASH_SOURCE[0]:+${BASH_SOURCE[0]##*/}}:${FUNCNAME[0]:+${FUNCNAME[0]}():}${LINENO}]: '
# BASH_XTRACEFD requires Bash 4.1+
exec 3>>"$debug_file"; BASH_XTRACEFD=3; set -o xtrace
# Ensure that xtrace and other optional options are enabled in all child processes started by 'fzf'.
execution_shell="$(which bash) -o xtrace -o errexit -o nounset -o pipefail -c"
fi
check_internet() {
if command ping -c 1 8.8.8.8 &>/dev/null; then
failure_command
else
echo "Internet is down."
fi
}
fzf --bind "start:become:check_internet" --with-shell "${execution_shell:-"$(which bash) -c"}" DEBUG_MODE=1 ./script.sh
# environment: line 1: failure_command: command not found
# [DEBUG] /var/folders/5f/ws8xbgdx55l69f6y7v20jd300000gn/T/tmp.pvAwlUJd The output file contains the encountered error from the I believe the UI goes to There are tools to remove the Footnotes |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
It's currently not possible. However, come to think of it, we can choose to write directly to diff --git a/src/tui/light.go b/src/tui/light.go
index 3ef8b60..4d3f58a 100644
--- a/src/tui/light.go
+++ b/src/tui/light.go
@@ -73,7 +73,7 @@ func (r *LightRenderer) csi(code string) string {
func (r *LightRenderer) flush() {
if r.queued.Len() > 0 {
- fmt.Fprint(os.Stderr, "\x1b[?7l\x1b[?25l"+r.queued.String()+"\x1b[?25h\x1b[?7h")
+ fmt.Fprint(r.ttyout, "\x1b[?7l\x1b[?25l"+r.queued.String()+"\x1b[?25h\x1b[?7h")
r.queued.Reset()
}
}
@@ -88,6 +88,7 @@ type LightRenderer struct {
prevDownTime time.Time
clicks [][2]int
ttyin *os.File
+ ttyout *os.File
buffer []byte
origState *term.State
width int
@@ -131,6 +132,10 @@ func NewLightRenderer(theme *ColorTheme, forceBlack bool, mouse bool, tabstop in
if err != nil {
return nil, err
}
+ out, err := openTtyOut()
+ if err != nil {
+ out = os.Stderr
+ }
r := LightRenderer{
closed: util.NewAtomicBool(false),
theme: theme,
@@ -138,6 +143,7 @@ func NewLightRenderer(theme *ColorTheme, forceBlack bool, mouse bool, tabstop in
mouse: mouse,
clearOnExit: clearOnExit,
ttyin: in,
+ ttyout: out,
yoffset: 0,
tabstop: tabstop,
fullscreen: fullscreen,
diff --git a/src/tui/light_unix.go b/src/tui/light_unix.go
index a5499a0..da675aa 100644
--- a/src/tui/light_unix.go
+++ b/src/tui/light_unix.go
@@ -14,6 +14,8 @@ import (
"golang.org/x/term"
)
+var tty string
+
func IsLightRendererSupported() bool {
return true
}
@@ -48,12 +50,14 @@ func (r *LightRenderer) closePlatform() {
// NOOP
}
-func openTtyIn() (*os.File, error) {
- in, err := os.OpenFile(consoleDevice, syscall.O_RDONLY, 0)
+func openTty(mode int) (*os.File, error) {
+ in, err := os.OpenFile(consoleDevice, mode, 0)
if err != nil {
- tty := ttyname()
+ if len(tty) == 0 {
+ tty = ttyname()
+ }
if len(tty) > 0 {
- if in, err := os.OpenFile(tty, syscall.O_RDONLY, 0); err == nil {
+ if in, err := os.OpenFile(tty, mode, 0); err == nil {
return in, nil
}
}
@@ -62,6 +66,14 @@ func openTtyIn() (*os.File, error) {
return in, nil
}
+func openTtyIn() (*os.File, error) {
+ return openTty(syscall.O_RDONLY)
+}
+
+func openTtyOut() (*os.File, error) {
+ return openTty(syscall.O_WRONLY)
+}
+
func (r *LightRenderer) setupTerminal() {
term.MakeRaw(r.fd())
}
diff --git a/src/tui/light_windows.go b/src/tui/light_windows.go
index 635b892..8c459d6 100644
--- a/src/tui/light_windows.go
+++ b/src/tui/light_windows.go
@@ -96,6 +96,11 @@ func openTtyIn() (*os.File, error) {
return nil, nil
}
+func openTtyOut() (*os.File, error) {
+ // not used
+ return nil, nil
+}
+
func (r *LightRenderer) setupTerminal() error {
if err := windows.SetConsoleMode(windows.Handle(r.outHandle), consoleFlagsOutput); err != nil {
return err And then your code works perfectly. And I actually like this approach better. Less chance of user errors of redirectly stderr, and it allows you to capture stderr from fzf and its child processes. fzf --bind 'enter:become:echo foo; echo bar >&2' > /tmp/foo 2> /tmp/bar Let's do this. Any concerns about the change? |
Beta Was this translation helpful? Give feedback.
It's currently not possible. However, come to think of it, we can choose to write directly to
/dev/tty
instead of tostderr
like so