[Python] linux system more basic command Python source sharing

Keywords: Python Linux

This python source code is the implementation of linux system more basic command.
Realize the basic function of more in linux. When a file name parameter is added after more, the split screen display will change pages according to space, change lines according to carriage return ', and the percentage will be displayed in the lower left corner.
To process the input of pipeline parameters, processing options + num: display from the specified line, + / String: find the string, display from the specified string

Running environment: linux system with PYTHON installed

Call example:
more.py [+num ] [+/pattern] filename
command|./more.py [+num ] [+/pattern]
more.p --help output help information
num is to display from the first few lines, and pattern is the string to find in the file

`#!/usr/bin/env python`

`# -*- coding:utf-8-*-`

`#File name: more.py`

`import` `os`

`import` `sys`

`import` `curses` `#Used to get the size of the terminal`

`import` `re` `#For character matching`

`import` `signal` `#For processing ctrl+c interrupt`

`import` `fcntl` `# Handling screen changes during display`

`import` `termios` `#Get terminal information`

`import` `struct`

`page_len` `=` `0`   `#The maximum number of lines that can be displayed when the screen is full`

`line_len` `=` `0`   `#Maximum number of bytes per line when the screen is full`

`sig_up` `=` `0`    `#Interrupt signal flag`

`winsz_chg` `=` `0`   `#Window size change flag`

`def` `win_sz_chg(signum, frame):`

`'''  Function function: this function is the processing function of screen change signal'''`

`global` `page_len, line_len, winsz_chg`

`winsz_chg` `=` `1`

`signal.signal(signal.SIGWINCH, signal.SIG_IGN)`

`s` `=` `struct.pack(``"HHHH"``,` `0``,` `0``,` `0``,` `0``) `

`a` `=` `struct.unpack(``'hhhh'``, fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ , s))`

`#Get the size of the current window`

`page_len` `=` `int``(a[``0``])` `-` `1`  `#Leave a line to show progress`

`line_len` `=` `int``(a[``1``])`

`signal.signal(signal.SIGWINCH, win_sz_chg)` `#Not calling will cause only one screen change to be detected`

`signal.signal(signal.SIGWINCH, win_sz_chg)` `#Receive processing window change signal`

`def` `term_do_exit(signum, frame):`

`'''  Function function: response function of keyboard interrupt signal'''`

`global` `sig_up`

`sig_up` `=` `1`           `#Set keyboard interrupt flag to 1`

`os.system(``"stty -F /dev/tty echo"``)` `#Restore the effective status of terminal output return`

`os.system(``"stty -F /dev/tty -cbreak"``)``#Reset the screen to the input character echo status`

`return`

`signal.signal(signal.SIGINT, term_do_exit)` `#Receive and process keyboard interrupt signals`

`def` `usage():`

`'''Display the meaning and calling format of each parameter of the script'''`

`print` `"-----------------usage-----------------"`

`print` `"1./more.py [+num] [+/pattern] filename"`

`print` `"2 command | ./more.py"`

`print` `"num: Start at line number num. "`

`print` `"pattern:Start at line number num."`

`print` `"space: next page"`

`print` `"q :do_exit the program"`

`print` `"enter:next line"`

`print``"----------------------------------------"`

`sys.exit()`

`def` `do_exit():`

`'''For system exit '''`

`os.system(``"stty -F /dev/tty echo"``)` `#Restore the effective status of terminal output return`

`os.system(``"stty -F /dev/tty -cbreak"``)``#Reset the screen to the input character echo status`

`sys.exit()`

`def` `is_input():`

`''' Check whether there is pipeline data input '''`

`try``:`

`f` `=` `sys.stdin.fileno()` `#There is pipeline input when judging`

`init_tty` `=` `termios.tcgetattr(f)` `#When there is no pipe input or parameter, the prompt will be displayed.`

`return` `0`

`except``:`

`return` `1`

`def` `get_line_num(args):`

`''' Gets the specified line to start display from the command line parameter`

`Parameters: args:Parameter return value obtained from the command line: the specified line to start display  '''`

`line_num` `=` `1`

`for` `i` `in` `args:` `#Match the number of rows to start from`

`ln` `=` `re.search(r``'\+\d+'``,` `str``(i))`

`if` `ln:`

`line_num` `=` `int``(ln.group().lstrip(``'+'``))``#Remove '+' with regular expression processing to get the line number to be displayed.`

`break`

`return` `line_num`

`def` `get_patstr(args):`

`'''Get the string to find from the command line`

`Parameters: args:The parameter obtained from the command line is the return value: the string to find:  '''`

`patstr` `=` `""`

`for` `i` `in` `args:` `#Get string to match`

`pa` `=` `re.search(r``'(\+\/\w*[^\s])'``,` `str``(i))`

`if` `pa:`

`break`

`if` `pa:`

`patstr` `=` `str``(pa.group().lstrip(``'+/'``))`

`return` `patstr`

`def` `get_args():`

`'''It is used to get parameters from the command line and parse parameters.`

`Return value:(line_num,patstr,fp):Specified line to start display, string to find, file object to operate on '''`

`line_num` `=` `1`

`patstr` `=` `""`

`args` `=` `sys.argv[``1``:]`

`if` `not` `args:`

`if` `is_input():` `#When there is no parameter, judge whether it is pipeline command input, not prompt for correct parameter input.`

`fp` `=` `sys.stdin`

`return` `(line_num, patstr, fp)`

`else``:`

`usage()`

`else``:`

`if` `args[``-``1``]` `=``=` `"--help"``:`

`usage()`

`line_num` `=` `get_l`

`2000`

`ine_num(args)`

`patstr` `=` `get_patstr(args)`

`if` `'+'` `not` `in` `args[``-``1``]:`

`filename` `=` `args[``-``1``]`

`if` `not` `os.path.exists(filename):`

`print` `" There is no file or directory"`

`do_exit()`

`else``:`

`fp` `=` `open``(filename)`

`else``:`

`if` `not` `is_input():`

`usage()`

`else``:`

`fp` `=` `sys.stdin`

`return` `(line_num, patstr, fp)`

`def` `get_screen_size():`

`''' Used to obtain the size of the file display terminal   '''`

`global` `page_len, line_len      `

`screen` `=` `curses.initscr()      `

`page_len, line_len` `=` `screen.getmaxyx()``#Get screen size`

`page_len` `=` `page_len` `-` `2`   `#Remove the command line and the last line to show more`

`curses.endwin()` `#If it doesn't end here, it will cause the following code to appear.`

`def` `show_more(pre_pg_len):`

`''' Wait for the keyboard to input the command, and carry out the corresponding processing.`

`:param pre_pg_len:The maximum number of lines that can be displayed before the screen changes'''`

`global`  `sig_up, winsz_chg, page_len`

`ft` `=` `open``(``'/dev/tty'``)` `#Open standard terminal input`

`sys.stdout.flush()` `#Refresh the cache output, otherwise there will be problems with the display`

`c` `=` `''`

`while` `True``:`

`try``:`

`c` `=` `ft.read(``1``)``#Read a character`

`except` `IOError:`

`if` `sig_up:`

`do_exit()` `#Keyboard interrupt exit program`

`if` `c` `=``=` `" "``:`

`print` `"\033[20D\033[K"` `#Control the cursor to return to the beginning of more -- anti white font, delete this line to achieve the effect that more does not scroll with the text`

`if` `winsz_chg:` `#If the screen size changes at this time, the number of full screen lines before the first return`

`winsz_chg` `=` `0`

`return` `pre_pg_len`

`else``:`

`return` `page_len` `#When the input is a space, it will be displayed in separate screens to display the next screen.`

`elif` `c` `=``=` `"q"``:`

`print` `"\033[20D\033[K"`

`return` `0`          `#Exit the display when the input is "q"`

`elif` `c` `=``=` `'\n'``:`

`print` `"\033[20D\033[K"``,`

`return` `1`           `#Display one more line when the input is line feed`

`def` `skip_ln(fp, line_num):`

`''' Read the file to the specified starting line  '''`

`n` `=` `line_num` `-` `1`

`while` `n:`

`fp.readline()`

`if` `not` `fp:`

`return`

`n` `=` `n` `-` `1`

`def` `search(fp, patstr):`

`''' Find the string to find in the file.`

`:param fp:File objects to display   `

`:param patstr:Search terms to find  '''`

`global`  `sig_up`

`text` `=` `' '`

`while` `True``:`

`try``:`

`s` `=` `fp.read(``1``)        `

`if` `not` `s:`

`print` `"can not find the string in the file"`

`do_exit()`

`text` `=` `text` `+` `s`

`if` `patstr` `in` `text:`

`return`

`except` `IOError:`

`if` `sig_up:`

`do_exit()`

`def` `show_prog(read_size, total_size):        `

`'''  In the lower left corner of the display screen"More"`

`When a file is to be displayed, the percentage of displayed files is also displayed`

`When a pipe input is displayed, only“ More"`

`:param read_size: Files already displayed`

`:param total_size:Total size of files to display  '''`

`if` `total_size:`

`prog` `=` `int``(read_size` `*` `100` `/` `float``(total_size))`

`print`  `"\033[7m --More--"` `+` `str``(prog)` `+` `'%'` `+` `"\033[0m"``,` `#Output the negative text "more" and the display percentage`

`else``:`

`print`  `"\033[7m --More--"` `+` `"\033[0m"``,` `#Output the negative text "more"`

`return`

`def` `do_more(fp , line_num , patstr):`

`'''Split screen display of file content`

`:param fp:File objects to display`

`:param page_len: Maximum number of rows to display`

`:param line_len:Maximum number of bytes that can be displayed per line   '''`

`global` `page_len, line_len`

`read_size` `=` `0`

`total_size` `=` `0`

`os.system(``"stty -F /dev/tty cbreak"``)` `#Call linux command to set the screen to unequal carriage return`

`os.system(``"stty -F /dev/tty -echo "``)``#Set the screen to input characters without echo`

`if` `fp !``=` `sys.stdin:`

`fp.seek(``0``,` `2``)` `#Gets the total number of bytes in the file to later display the percentage of output`

`total_size` `=` `fp.tell()`

`fp.seek(``0``,` `0``)`

`if` `line_num !``=` `1``:`

`skip_ln(fp, line_num)`

`if` `patstr:`

`search(fp, patstr)`

`try``:`

`line` `=` `fp.readline(line_len)``#To read the file by line, you can set the maximum number of words to read. When "\ n" is encountered, read "\ n" to the end. `

`read_size` `=` `len``(line)`

`num_lns` `=` `0`

`while` `line:`

`if` `num_lns` `=``=` `page_len:` `#Wait for the command every time the output screen is full`

`pre_pg_len` `=` `page_len`

`show_prog(read_size, total_size)`

`reply` `=` `show_more(pre_pg_len)          `

`if` `reply` `=``=` `0``:`

`break`

`num_lns` `-``=` `reply`

`print` `line.strip(``'\n'``)` `#Use to remove line breaks from print output`

`sys.stdout.flush()` `#Refresh the cache, otherwise the file display will be slow`

`read_size` `=` `read_size` `+` `len``(line)`

`num_lns` `+``=` `1`

`line` `=` `fp.readline(line_len)`

`fp.close()`

`except` `IOError:`

`if` `sig_up:`

`do_exit()`

`if` `__name__` `=``=` `'__main__'``:`

`get_screen_size()` `#Get the size of the display terminal`

`(line_num, patstr, fp)` `=` `get_args()`

`do_more(fp, line_num, patstr)`

`do_exit()`
Python Resource sharing qun: 855408893  There is an installation package in it. Learn video materials and live broadcast real cases for free. Here is Python Learners' gathering place, zero foundation, advanced, welcome

Posted by crabfinger on Thu, 31 Oct 2019 22:41:59 -0700