[ATUALIZAÇÃO] Obrigado pelos comentários e pensamentos até agora. Com base neles, atualizei e expandi a pergunta original com mais informações e exemplos.
Vamos supor que não haja nenhum caso de uso real por enquanto. O único objetivo é descobrir se isso é possível e, se for, como.
Quero executar um script e determinar se ele é executado diretamente pelo usuário ou chamado dentro de outro script. Também quero verificar se ele é originado ou não.
Isso significa que há 4 casos de teste principais:
- executado no terminal, não originado
- executar no terminal, originado
- executar em script (não em terminal), não originado
- executar em script (não em terminal), originado
Meu cérebro enferrujado, o Google e o ChatGPT me deram uma lista de verificações para testar se estavam sendo executadas em um terminal, mas nenhuma delas está dando resultados corretos em todas as 4 chamadas.
Os testes estão prontos check-term
e há um script de chamada check-term-driver
, ambos abaixo.
Se eu executar os 4 casos de teste na ordem dada acima, para que um determinado número de teste esteja correto (digamos, o número de teste n), quero que a saída seja:
n: in terminal: not sourced: ...
n: in terminal: sourced: ...
n: not in terminal: not sourced: ...
n: not in terminal: sourced: ...
O teste para saber se há ou não origem está correto em todas as 4 chamadas.
script de verificação de termo:
#!/usr/bin/env bash
IS_TERMINAL=true
NOT_TERMINAL=false
TEST_NUM=0
SOURCED_TEXT="undefined"
print_result() {
TEST_NUM=$((TEST_NUM + 1))
if [ "$1" = "$IS_TERMINAL" ]; then
printf "%2d: %-16s %-12s %s\n" "$TEST_NUM" "in terminal:" "$SOURCED_TEXT:" "$2"
else
printf "%2d: %-16s %-12s %s\n" "$TEST_NUM" "not in terminal:" "$SOURCED_TEXT:" "$2"
fi
}
# First check if script is sourced or not.
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
SOURCED_TEXT="not sourced"
else
SOURCED_TEXT="sourced"
fi
# Tests run individually in expanded if/else for clarity.
# - test condition described by the result text.
if [ -t 0 ]; then
print_result "$IS_TERMINAL" "stdin is a terminal"
else
print_result "$NOT_TERMINAL" "stdin is not a terminal"
fi
if [ -t 1 ]; then
print_result "$IS_TERMINAL" "stdout is a terminal"
else
print_result "$NOT_TERMINAL" "stdout is not a terminal"
fi
if [ -t 2 ]; then
print_result "$IS_TERMINAL" "stderr is a terminal"
else
print_result "$NOT_TERMINAL" "stderr is not a terminal"
fi
if [[ "$-" == *i* ]]; then
print_result "$IS_TERMINAL" "interactive shell"
else
print_result "$NOT_TERMINAL" "non-interactive shell"
fi
if [ -n "$(tty)" ]; then
print_result "$IS_TERMINAL" "has a controlling terminal"
else
print_result "$NOT_TERMINAL" "does not have a controlling terminal"
fi
if [ -p /dev/stdin ]; then
print_result "$NOT_TERMINAL" "running in a pipeline"
else
print_result "$IS_TERMINAL" "not running in a pipeline"
fi
if [ -z "$(jobs -p)" ]; then
print_result "$IS_TERMINAL" "running in foreground"
else
print_result "$NOT_TERMINAL" "running in background"
fi
# Get ID of process that started the script.
PPID_VALUE=$(ps -o ppid= -p $$ | awk 'NR==2 {print $1}')
# If ID can't be found, give it a default value.
[ -z "$PPID_VALUE" ] && PPID_VALUE=1
# Check if attached or not.
if [ "$PPID_VALUE" -ne 1 ]; then
print_result "$IS_TERMINAL" "attached to a parent process"
else
print_result "$NOT_TERMINAL" "detached from a parent process"
fi
# Check if the parent process is a shell
PARENT_CMD=$(ps -o args= -p "$PPID_VALUE" 2>/dev/null)
if echo "$PARENT_CMD" | grep -qE '/(bash|zsh|sh)(\s|$)'; then
print_result "$IS_TERMINAL" "parent process is a shell"
else
print_result "$NOT_TERMINAL" "parent process is not a shell"
fi
Script do driver:
#!/usr/bin/env bash
./check-term
echo ""
. ./check-term