Como obter o nome real do terminal de controle (se houver um, senão um erro) como um nome de caminho?
Por "nome real", quero dizer que não /dev/tty
, que não pode ser usado por outros processos arbitrários para se referir ao mesmo terminal. Prefiro a resposta como um código shell simples (como o exemplo abaixo), se possível, caso contrário, como uma função C.
Observe que isso deve funcionar mesmo que a entrada padrão seja redirecionada, para que o tty
utilitário não possa ser usado: not a tty
nesse caso, ocorreria um erro, pois tty
apenas imprime o nome do arquivo do terminal conectado à entrada padrão.
No Linux, pode-se usar:
echo "/dev/`ps -p $$ -o tty | tail -n 1`"
mas isso não é portátil, pois de acordo com o POSIX, o formato do nome do terminal não é especificado .
Em relação às funções C, ctermid (NULL)
retorna /dev/tty
, que é inútil aqui.
Nota: de acordo com a zsh
documentação, deve-se poder fazer
zsh -c 'echo $TTY'
mas isso atualmente (versão 5.0.7) falha quando a entrada e a saída padrão são redirecionadas:
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null
/dev/pts/9
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null > /dev/null
/dev/tty
fonte
ps
solução cobre a maioria dos sistemas (ewho
não ajuda mais do queps
), possivelmente com um pouco mais de código para lidar com o identificador sozinho (como "04"). Fiquei me perguntando se havia uma solução ainda mais portátil.man xterm
:-Sccn
Esta opção permitexterm
ser usada como um canal de E / S para um programa existente ... O valor da opção são algumas letras do nome de um pty para usar no modo escravo, mais o número fd herdado. Se a opção contiver um caractere "/", delimitará o nome do pty do fd.ps
de busybox (que é usado pelo Android, BTW), mesmo sob GNU / Linux. O que você quer dizer com "xterm
pode lidar com isso04
"?busybox
não é compatível com POSIX.toybox
, no entanto, faz muito bem.Respostas:
O "terminal de controle" aka. ctty, distingue-se " do terminal com o qual o processo está interagindo".
A maneira padrão de obter o caminho do ctty é o ctermid (3). Ao chamar isso, no freebsd desde o release 10, um caminho real é pesquisado [1], enquanto as implementações mais antigas do freebsd e glibc [2] retornam incondicionalmente "/ dev / tty"].
ps (1) do pacote linux procps 3.2.8, leia a entrada numérica em / proc / * / stat [3] e deduza o nome do caminho parcialmente adivinhando [4, 5] devido à falta de suporte do sistema [6] .
No entanto, se não estivermos estritamente interessados no ctty, mas em qualquer terminal associado ao stdio, o tty (1) imprime o caminho do terminal conectado ao stdin, que é idêntico ao
ttyname(fileno(stdin))
do c, e uma alternativa éreadlink /proc/self/fd/0
.Pensamento menos importante em relação ao comportamento incondicional "/ dev / tty": as especificações apenas dizem que a string retornada pelo ctermid "quando usada como nome do caminho, refere-se ao terminal de controle atual", em vez de algo simples "é o nome do caminho do atual terminal de controle ". Pode ser interpretado como "/ dev / tty" não é o terminal de controle, mas apenas se refere ao terminal de controle se o mesmo processo o abrir (3). Portanto, não violar a regra "um terminal pode ser complicado para no máximo uma sessão" [7].
Outra conseqüência é que, quando estou sem um terminal de controle, o ctermid não falha - essa falha é permitida pelas especificações [8] -, de modo que só posso ficar ciente da minha ausência de ctty'less até falhar em uma abertura subsequente (3), o que é bom, já que as especificações também dizem que a abertura (3) não é garantida para ter sucesso.
fonte
ps
solução que dei na minha pergunta, pois nem todos os sistemas operacionais têm um/proc
sistema de arquivos. Observe queps
ele mesmo usa um link de leitura ativado/proc/self/fd/2
(que funciona mesmo, o erro padrão é redirecionado).tty
.stderr
é provavelmente o melhor, porque deve ser aberto r / w. Entãotty <&2
.ctermid()
sempre retorna"/dev/tty"
. Esse nome sempre se refere ao terminal de controle do processo que o acessa , que varia de acordo com a sessão. O terminal é específico da sessão, mas o nome pelo qual é acessado não precisa ser.A especificação POSIX realmente protege suas apostas no que diz respeito ao Terminal de Controle e define assim:
/dev/tty
é um sinônimo para o terminal de controle associado a um processo.Está na lista de definições - e é tudo o que existe. Mas na Interface Geral do Terminal , mais um pouco é dito:
Um terminal pode pertencer a um processo como seu terminal de controle. Cada processo de uma sessão que possui um terminal de controle possui o mesmo terminal de controle. Um terminal pode ser o terminal de controle por no máximo uma sessão. O terminal de controle de uma sessão é alocado pelo líder da sessão de uma maneira definida pela implementação. Se um líder de sessão não tiver um terminal de controle e abrir um arquivo de dispositivo de terminal que ainda não esteja associado a uma sessão sem usar a opção O_NOCTTY (consulte open ()), será definido como implementação se o terminal se tornará o terminal de controle da sessão líder.
O terminal de controle é herdado por um processo filho durante uma chamada de função fork (). Um processo renuncia ao seu terminal de controle quando cria uma nova sessão com o
setsid()
função; outros processos restantes na sessão antiga que possuíam esse terminal como seu terminal de controle continuam a ter. Após o fechamento do último descritor de arquivo no sistema (se está ou não na sessão atual) associado ao terminal de controle, não é especificado se todos os processos que tinham esse terminal como terminal de controle deixam de ter qualquer terminal de controle. Não é especificado se e como um líder de sessão pode recuperar um terminal de controle depois que o terminal de controle foi abandonado dessa maneira. Um processo não renuncia ao seu terminal de controle simplesmente fechando todos os descritores de arquivo associados ao terminal de controle se outros processos continuarem a abri-lo.Ainda há muita coisa não especificada - e honestamente acho que faz sentido. Embora o terminal seja uma interface principal do usuário, em alguns casos também existem todos os tipos de outras coisas - como hardware real ou até mesmo um tipo de impressora - mas em muitos casos praticamente não é praticamente nada - como um
xterm
que é apenas um emulador . É difícil ser específico lá - e eu não acho que seria muito do interesse do Unix, porque os terminais fazem muito mais do que o Unix.De qualquer forma, o POSIX também é bastante duvidoso sobre como
ps
deve se comportar no que diz respeito ao ctty.Aqui está o
-a
interruptor:Ótimo. Os líderes da sessão podem ser omitidos. Isso não é muito útil.
E
-t
:<blank>
ou separada por vírgula. Os identificadores de terminal devem ser fornecidos em um formato definido pela implementação .... que é outra decepção. Mas continua dizendo isso sobre os sistemas XSI:
tty04
) ou, se o nome do arquivo do dispositivo começartty
, apenas o identificador após os caracterestty
(por exemplo04
) .Isso é um pouco melhor, mas não é um caminho. Também em sistemas XSI, há o
-d
switch:... o que é pelo menos claro. Você pode especificar a
-o
opção utput também com atty
string format, mas, como você observou, o formato de saída é definido pela implementação. Ainda assim, acho que é o melhor possível. Eu acho que - com muito trabalho - as opções acima, combinadas com outros utilitários, podem lhe proporcionar uma estimativa muito boa. Para ser sincero, porém, não sei quando / como isso acontece para você - e não pude imaginar uma situação em que isso aconteceria. Mas acho que provavelmente se adicionarmosfuser
efind
podemos verificar o caminho.O
/dev/null
material era apenas para mostrar que poderia funcionar quando nenhum dos subconjuntos de pesquisa tinha 0,1,2 conectado ao ctty. Enfim, isso imprime:Agora, o texto acima mostra o caminho completo na minha máquina, e imagino que seria para a maioria das pessoas na maioria dos casos. Eu também posso imaginar que poderia falhar. São apenas heurísticas grosseiras.
Provavelmente, isso pode falhar por muitas outras razões, mas se você estiver em um sistema que permita ao líder da sessão renunciar a todos os descritores ao ctty e ainda assim permanecer como sid, conforme a especificação permitir, isso definitivamente não ajudará. Dito isto, acho que isso pode obter uma estimativa muito boa na maioria dos casos.
Claro que a coisa mais fácil de fazer se você tiver algum descritor conectado ao seu ctty é apenas ...
...ou similar.
fonte