Если вы не против слияния stdout и stderr, возможно, проще всего запустить с флагом -x
, который заставляет bash печатать каждую команду, поскольку она выполняется с префиксом типа +++
, где количество символов зависит от уровня вложенности. Затем вы можете постобработать вывод, запомнив префикс, но подавив строку и применив ее к любой следующей строке без префикса, которая будет вашим echo или printf.
Например, возьмите небольшой факториальный сценарий, myprog
:
#!/bin/bash
f(){
local i=$1
if [[ "$i" > 1 ]]
then echo $((i*$(f $((i-1)))))
else echo $i
fi
echo "my debug info $i" >&2
}
echo "factorial ${1?} is $(f $1)"
Запуск его с
bash -x myprog 4 |&
awk '/^+/{ indent=$1; next }
{ print indent " " $0 }'
дает вам
+++++ my debug info 1
++++ my debug info 2
+++ my debug info 3
++ my debug info 4
+ factorial 4 is 24
Конечно, вы можете получить неплохой результат отладки с номерами строк, именами файлов, и функции, просто установив PS4
с помощью -x
. Например,
PS4='+ ${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]} - [${SHLVL},${BASH_SUBSHELL}, $?] '
дает вам:
++ myprog:10: main - [2,1, 0] f 4
++ myprog:3: f - [2,1, 0] local i=4
++ myprog:4: f - [2,1, 0] [[ 4 > 1 ]]
+++ myprog:5: f - [2,2, 0] f 3
+++ myprog:3: f - [2,2, 0] local i=3
+++ myprog:4: f - [2,2, 0] [[ 3 > 1 ]]
++++ myprog:5: f - [2,3, 0] f 2
++++ myprog:3: f - [2,3, 0] local i=2
++++ myprog:4: f - [2,3, 0] [[ 2 > 1 ]]
...
mosh
использует среду локали, поддерживаемую ssh
. Хотя mosh
, очевидно, не имеет verbose- или debug-опций, вы можете указать ему, какую ssh
команду использовать при подключении, и, добавив опцию -vvv
, заставить ssh
показать, какие переменные локали он отправляет.
Например, начиная с
mosh -ssh='ssh -vvv' root@server
вы можете увидеть
debug1: Sending env LC_ALL = C
debug2: channel 0: request env confirm 0
для POSIX, и
debug1: Sending env LC_CTYPE = en_US.UTF-8
debug2: channel 0: request env confirm 0
которые показывают, что сервер подтверждает переменные, которые используются. Удаленный sshd
может игнорировать некоторые из вашего окружения в зависимости от настройки AcceptEnv
в конфигурации для sshd
- или настроек SendEnv
вашего пользователя (в конфигурации ssh
).
Не все серверы принимают ваши переменные локали через ssh.
Даже если конфигурация настроена разрешительно, все равно возможно (особенно если вы подключаетесь к пользователю root), что кто-то решил, что локаль для этого пользователя должна быть POSIX. Для root это имеет определенный смысл, поскольку при копировании select/paste у вас будет меньше проблем.
Например, некоторые системы используют /etc/profile.d/lang.sh
для установки локали для интерактивного использования. Этот скрипт отличается в разных системах, и это второе место (после конфигураций ssh/sshd), на которое следует обратить внимание при поиске объяснения, почему информация о локали не передается удаленной системе. В Red Hat (CentOS) скрипт пытается получить информацию из системной и домашней конфигурации, например,
if [ -n "$LANG" ]; then
saved_lang="$LANG"
[ -f "$HOME/.i18n" ] && . "$HOME/.i18n" && sourced=1
LANG="$saved_lang"
unset saved_lang
else
for langfile in /etc/locale.conf "$HOME/.i18n" ; do
[ -f $langfile ] && . $langfile && sourced=1
done
fi
SuSE отличается, делая предположения о ssh и gdm до чтения по сути тех же файлов:
#
# lang.sh: Set interactive language environment
#
# Used configuration files:
#
# /etc/sysconfig/language
# $HOME/.i18n
#
#
# Already done by the remote SSH side
#
test -z "$SSH_SENDS_LOCALE" || return
#
# Already done by the GDM
#
test -z "$GDM_LANG" || return
Для ваших конкретных серверов (версия не указана) скрипт может отличаться от одного выпуска к другому. Мои серверы Debian не имеют такого файла - и полагаются на системную локаль по умолчанию и gdm (которые могут отличаться) для установки интерактивной локали. Ваше ssh-соединение может использовать другое значение системной локали, чем интерактивный сеанс с использованием X (через gdm). В этом случае нужно исправить системную локаль (см. Locale в Debian wiki).
user@machine:~$ LC_ALL="en_US.UTF-8" mosh-server