Linux получить размер терминала

jtriley / terminalsize.py

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

#!/usr/bin/env python
import os
import shlex
import struct
import platform
import subprocess
def get_terminal_size ():
«»» getTerminalSize()
— get width and height of console
— works on linux,os x,windows,cygwin(windows)
originally retrieved from:
http://stackoverflow.com/questions/566746/how-to-get-console-window-width-in-python
«»»
current_os = platform . system ()
tuple_xy = None
if current_os == ‘Windows’ :
tuple_xy = _get_terminal_size_windows ()
if tuple_xy is None :
tuple_xy = _get_terminal_size_tput ()
# needed for window’s python in cygwin’s xterm!
if current_os in [ ‘Linux’ , ‘Darwin’ ] or current_os . startswith ( ‘CYGWIN’ ):
tuple_xy = _get_terminal_size_linux ()
if tuple_xy is None :
print «default»
tuple_xy = ( 80 , 25 ) # default value
return tuple_xy
def _get_terminal_size_windows ():
try :
from ctypes import windll , create_string_buffer
# stdin handle is -10
# stdout handle is -11
# stderr handle is -12
h = windll . kernel32 . GetStdHandle ( — 12 )
csbi = create_string_buffer ( 22 )
res = windll . kernel32 . GetConsoleScreenBufferInfo ( h , csbi )
if res :
( bufx , bufy , curx , cury , wattr ,
left , top , right , bottom ,
maxx , maxy ) = struct . unpack ( «hhhhHhhhhhh» , csbi . raw )
sizex = right — left + 1
sizey = bottom — top + 1
return sizex , sizey
except :
pass
def _get_terminal_size_tput ():
# get terminal width
# src: http://stackoverflow.com/questions/263890/how-do-i-find-the-width-height-of-a-terminal-window
try :
cols = int ( subprocess . check_call ( shlex . split ( ‘tput cols’ )))
rows = int ( subprocess . check_call ( shlex . split ( ‘tput lines’ )))
return ( cols , rows )
except :
pass
def _get_terminal_size_linux ():
def ioctl_GWINSZ ( fd ):
try :
import fcntl
import termios
cr = struct . unpack ( ‘hh’ ,
fcntl . ioctl ( fd , termios . TIOCGWINSZ , ‘1234’ ))
return cr
except :
pass
cr = ioctl_GWINSZ ( 0 ) or ioctl_GWINSZ ( 1 ) or ioctl_GWINSZ ( 2 )
if not cr :
try :
fd = os . open ( os . ctermid (), os . O_RDONLY )
cr = ioctl_GWINSZ ( fd )
os . close ( fd )
except :
pass
if not cr :
try :
cr = ( os . environ [ ‘LINES’ ], os . environ [ ‘COLUMNS’ ])
except :
return None
return int ( cr [ 1 ]), int ( cr [ 0 ])
if __name__ == «__main__» :
sizex , sizey = get_terminal_size ()
print ‘width =’ , sizex , ‘height =’ , sizey

Источник

Как изменить размер терминала пользователя Ubuntu

Изменить размер терминала BASH скриптом бывает нужно для того чтобы Desktop приложение правильно отрабатывало и отображалось на экране пользователя. Задать необходимый размер можно в качестве условия продолжения программы.

Изменяем размер терминала одной командой в bash

Сделать это можно следующей командой:

Параметры задаются в количестве строк и столбцов. Первое значение относится к высоте терминала, второе к его ширине.

resize -s будет гарантировано корректно работать на рабочих станциях, использующих графическую оболочку GNOME. При использовании других сред рабочего стола положительный результат не гарантирован.

Варьируя значения параметров можно изменять размер терминала в режиме реального времени.

Изменить размер терминала bash

При выполнении команды определяется значение переменных, затем они экспортируются.

Если на рабочей станции пользователя используется какая-либо другая среда рабочего стола — можно обойтись без использования resize -s, а непосредственно передавать необходимые значения переменных, затем экспортируя их.

Код скрипта при этом становится несколько объёмнее, однако никаких трудностей при его написании также возникнуть не должно.

Как узнать текущий размер терминала

В системе хранится ряд определенных переменных, посмотреть их все можно введя в консоли символ $

Читайте также:  Linux аналог mac os

Среди них будут переменные

$COLUMNS
$LINES

Именно в них задаются значения ширины и высоты окна терминала, и именно значения этих переменных переопределяются командой resize -s.

Значения параметров можно вывести следующим образом

Размер рядов и колонок неодинаков, поэтому ввод одинаковых численных значений квадратного терминала не даст.

Использоваться данные переменные могут в выражениях if; then в скриптах в тех случаях когда важно получить размер терминала, не меньше определенного размера для того чтобы информация отображалась корректно.

Рационально установить минимальный размер терминала пользователя при котором информация отображается верно в качестве необходимого условия выполнения программы, в противном случае можно либо принудительно изменять размер терминала либо выдавать предупреждение и рекомендацию сделать это самостоятельно.

Основное применение изменения размера терминала — пользовательские интерфейсы, любой из них представляет собой скрипт и определенный алгоритм, и используется функции и операторы (такие как case).

Источник

unixforum.org

есть ли способы получить размер терминала, не используя ioctl?
можно ли это сделать с помощью tcgetattr()?
заранее спасибо за помощь?

Re: получить размер терминала.

Сообщение krivakin » 11.03.2006 19:33

Asgard Сообщения: 215 Статус: North Valfader Контактная информация:

Re: получить размер терминала.

Сообщение Asgard » 11.03.2006 22:49

ncurses не катит. слишком монструозная вещь для такой маленькой задачи. а про ctio поподробнее можно?

polachok Бывший модератор Сообщения: 2199 Статус: главный форумный маргинал ОС: gnu/linux Контактная информация:

Re: получить размер терминала.

Сообщение polachok » 11.03.2006 23:48

NAME
resize — set TERMCAP and terminal settings to current xterm window size

Asgard Сообщения: 215 Статус: North Valfader Контактная информация:

Re: получить размер терминала.

Сообщение Asgard » 12.03.2006 11:59

polachok
resize только устанавливает нужные env для xterm’a, а он уже получает информацию и в соответсвии с ней меняет размер. т.е. реализация лежит на нём. т.о. если ковырять сорцы, то имеенно xterm’a.

p/s
меня терзают смутные сомнения, что в xterm’e это реализовано как раз с помощью ioctl().

Re: получить размер терминала.

Сообщение krivakin » 12.03.2006 17:07

Похоже по функциональности на ncurses но ИМХО намного пороще и есть вожможность работать с мышью.
Можешь почитать здесь и здесь.
Несмотри что там о редакторах просто найди там ссылку на этот пакет. В нем разобраться очень просто к тому же есть неплохие примеры.

Asgard Сообщения: 215 Статус: North Valfader Контактная информация:

Re: получить размер терминала.

Сообщение Asgard » 12.03.2006 17:46

я против ncurses ничего не имею, но мне на фиг не нужна вся её функциональность. мне просто нужно узнать размер терминала. пока я для этого использую ioctl().

Можешь почитать здесь и здесь.
Несмотри что там о редакторах просто найди там ссылку на этот пакет. В нем разобраться очень просто к тому же есть неплохие примеры.

спасибо за ссылки.
/* честно говоря смешнон подход автора. ‘идеальный’ тр == ‘винодовый’ тр. бугога */

там это делается тоже с помощью ioctl(). по ходу дела, другого способа, видимо, на данный момент не существует. а жаль.

Источник

Getting terminal width in C?

I’ve been looking for a way to get the terminal width from within my C program. What I keep coming up with is something along the lines of:

#include #include int main (void)
austin@:~$ gcc test.c -o test test.c: In function ‘main’: test.c:6: error: storage size of ‘ts’ isn’t known test.c:7: error: ‘TIOCGSIZE’ undeclared (first use in this function) test.c:7: error: (Each undeclared identifier is reported only once test.c:7: error: for each function it appears in.) 

Is this the best way to do this, or is there a better way? If not how can I get this to work? EDIT: fixed code is

#include #include int main (void)

8 Answers 8

Have you considered using getenv() ? It allows you to get the system’s environment variables which contain the terminals columns and lines.

Читайте также:  Inodes used in linux

Alternatively using your method, if you want to see what the kernel sees as the terminal size (better in case terminal is resized), you would need to use TIOCGWINSZ, as opposed to your TIOCGSIZE, like so:

struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); 
#include #include #include int main (int argc, char **argv) < struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); printf ("lines %d\n", w.ws_row); printf ("columns %d\n", w.ws_col); return 0; // make sure your main returns int >

It doesn’t provide you the current terminal size, if someone resizes the terminal during the program’s execution.

Although we can see the LINES and COLUMNS variables in the environment, they don’t seem to be exported. So not accessible from your C program.

Just stumbled upon this answer, and my jaw dropped when I realized that getenv(«COLUMNS») works perfectly when running under watch(1). So now I have a set of fallbacks, all from the TIOCWINSZ ioctl, to getenv if not a tty, down to the classic ANSI escape «move cursor to 9999,9999 and the query cursor pos. The last one works on serial consoles for embedded systems 🙂

This example is a bit on the lengthy side, but I believe it’s the most portable way of detecting the terminal dimensions. This also handles resize events.

As tim and rlbond suggests, I’m using ncurses. It guarantees a great improvement in terminal compatability as compared to reading environment variables directly.

#include #include #include // SIGWINCH is called when the window is resized. void handle_winch(int sig) < signal(SIGWINCH, SIG_IGN); // Reinitialize the window to update data structures. endwin(); initscr(); refresh(); clear(); char tmp[128]; sprintf(tmp, "%dx%d", COLS, LINES); // Approximate the center int x = COLS / 2 - strlen(tmp) / 2; int y = LINES / 2 - 1; mvaddstr(y, x, tmp); refresh(); signal(SIGWINCH, handle_winch); >int main(int argc, char *argv[]) < initscr(); // COLS/LINES are now set signal(SIGWINCH, handle_winch); while(getch() != 27)< /* Nada */ >endwin(); return(0); > 

But is it really safe to call initscr and endwin from a signal handler? They’re at least not listed among the async-signal-safe APIs in man 7 signal

That’s a good point @nav, I’ve never thought of that! Would a better solution perhaps be to have the signal handler raise a flag, and then perform the rest of the operations in the main loop?

#include #include #include #include static char termbuf[2048]; int main(void) < char *termtype = getenv("TERM"); if (tgetent(termbuf, termtype) < 0) < error(EXIT_FAILURE, 0, "Could not access the termcap data base.\n"); >int lines = tgetnum("li"); int columns = tgetnum("co"); printf("lines = %d; columns = %d.\n", lines, columns); return 0; > 

Needs to be compiled with -ltermcap . There is a lot of other useful information you can get using termcap. Check the termcap manual using info termcap for more details.

@einpoklum This is nearly three years later yet, but isn’t it fairly clear that 2048 is just an arbitrary size for the buffer that «should probably be big enough» for whatever input string is going there?

Читайте также:  Linux для php разработки

For anyone curious, the 2048 buffer size is explained in the GNU termcap documentation here: gnu.org/software/termutils/manual/termcap-1.3/html_mono/… There’s also a lot of other stuff in there people reading this post may find useful.

If you have ncurses installed and are using it, you can use getmaxyx() to find the dimensions of the terminal.

To add a more complete answer, what I’ve found to work for me is to use @John_T’s solution with some bits added in from Rosetta Code, along with some troubleshooting figuring out dependencies. It might be a bit inefficient, but with smart programming you can make it work and not be opening your terminal file all the time.

#include #include #include // ioctl, TIOCGWINSZ #include // err #include // open #include // close #include // don't remember, but it's needed struct WinSize < size_t rows; size_t cols; >; struct WinSize get_screen_size() < struct winsize ws; int fd; fd = open("/dev/tty", O_RDWR); if(fd < 0 || ioctl(fd, TIOCGWINSZ, &ws) < 0) err(8, "/dev/tty"); struct WinSize size; size.rows = ws.ws_row; size.cols = ws.ws_col; close(fd); return size; >

If you make sure not to call it all but maybe every once in a while you should be fine, it should even update when the user resizes the terminal window (because you’re opening the file and reading it every time).

Oh, and don’t forget to free() the result .

Why would you return size_t * ? Just make a struct for that and return the struct value. This way there is no malloc() and no free() involved.

My Version Is An extermination of the ioctl approach I am not allocating memory and passing the struct back by value I believe so no memory leaks here

#include #include // ioctl, TIOCGWINSZ struct winsize get_screen_size(); unsigned short get_screen_width(); unsigned short get_screen_height(); void test_screen_size(); 

The implementation, I have also added a test function that fills in the terminal with a box padded by one char all the way around

/** * Implementation of nos_utils signatures */ #include #include #include // ioctl, TIOCGWINSZ #include // err #include // open #include // close //#include // doesnt seem to be needed for this #include "nos_utils.h" /** * @return struct winsize * unsigned short int ws_row; * unsigned short int ws_col; * unsigned short int ws_xpixel; * unsigned short int ws_ypixel; */ struct winsize get_screen_size() < struct winsize ws; int fd; fd = open("/dev/tty", O_RDWR); if (fd < 0 || ioctl(fd, TIOCGWINSZ, &ws) < 0) err(8, "/dev/tty"); close(fd); // dont forget to close files return ws; >unsigned short get_screen_width() < struct winsize ws = get_screen_size(); return ws.ws_col; >unsigned short get_screen_height() < struct winsize ws = get_screen_size(); return ws.ws_row; >void test_screen_size() < struct winsize ws = get_screen_size(); // unsigned short h = ws.ws_row; // unsigned short w = ws.ws_col; printf("The Teminal Size is\n rows: %zu in %upx\n cols: %zu in %upx\n", ws.ws_row, ws.ws_ypixel, ws.ws_col, ws.ws_xpixel); unsigned short h = get_screen_height(); unsigned short w = get_screen_width(); h = h - 4; //for the 3 lines above + 1 fro new terminal line after :) for (unsigned short i = 0; i < h; i++) //one space buffer around edge else if (i == 0 || i == h - 1 || j == 0) < printf(" "); >//the up arrows else if (i == 1) < printf("^"); >else if (i == h - 2) < printf("v"); >else if (j == 1) < printf("<"); >else if (j == w - 2) < printf(">"); > else < printf("#"); >>//end col >//end row > int main(int argc, char** argv)

Источник

Оцените статью
Adblock
detector