제목이 좀 이상한데...
"A shell utility allowing users to navigate to aliased directories"와 비스무리 한 것이다.
10여 년 전 리눅스에서 개발할 때 디렉터리 이동이 귀찮아 ncurses 라이브러리 이용해서 C언어로 UI 만들고 shell 스크립트로 실행해서 사용했었는데, 소스코드를 못 찾겠어서 인터넷 뒤지다 보니 아래와 같은 프로그램을 찾았다.
https://github.com/iridakos/goto
자동 완성 기능도 지원되고 아주 좋은 프로그램이다. 그런데 문제는 이것조차도 귀찮다는 것이다. 그냥 키보드 상하 키로 선택해서 엔터 치고 싶었다. 예전에 만든 것을 찾는 것은 포기했으니 만들어야지 어쩌겠는가 ㅠㅠ
예전에는 ncurses로 만들었는데 이제 머리가 썩어서 바닥부터 하기가 힘들다. 그래서 인터넷 뒤져서 python으로 만든 ncurses 예제를 구했다. 출처를 써야 하는데 까먹어서.... 아무튼 이 python 코드로 ncurses 부분 해결하고 나머지는 옛날 기억 더듬어서 비슷하게 만들었다. (예전 것이 더 예뻤는데...)
크게
1) 디렉터리 목록 파일 읽기
2) 화면 그리는 부분
3) 실행을 위한 shell script 및 .bashrc 수정
1) 디렉터리 목록 파일 읽기
file_path = sys.argv[1]
list_file = sys.argv[2]
with open(list_file) as f:
global golist_strings
golist_strings = [tuple(map(lambda str:str.replace('\"', '').strip(), i.split(','))) for i in f]
golist_cnt = len(golist_strings)
max = 3
for go in golist_strings :
len_go = len(go[0]) + len(go[1]) + 3;
if (len_go > max) :
max = len_go
max_line_length = max
offset_y = 2 + display_per_page;
file_path는 옮겨갈 path를 shell script로 넘기는 용도로 만들었는데, 예전에는 이렇게 하지 않았는데 기억이 나지 않아 대충 했다. 그리고 list_file은 디렉터리 목록이 있는 파일이다.
list_file 읽고 처리하는 것은 이전 게시물을 확인해 주시고...
나머지 부분은 화면 상의 위치 잡기 위해 문자열 길이 등을 계산하는 코드로 크게 중요하지 않다.
2021.07.26 - [일하기/Python] - map function 안에서 문자열 strip 및 replace 하기
2) 화면 그리는 부분
소스 코드는 마지막에 있는 전체 코드를 참조하시면 되고... 대략 이런 형태로 간단하게 구성했다. 가운데에 목록 그리고 하단에 'q'를 누르면 나간다는 문구 정도다. 그리고 예외 처리를 하지 않아 터미널 크기를 아주 작게 만들면 예외가 발생하여 죽는다. 그냥 막 쓸 용도라 ㅎㅎㅎ
3) 실행을 위한 shell script 및 .bashrc 수정
#!/bin/bash
TMP_FILE=/tmp/`openssl rand -hex 32`
#echo $TMP_FILE
python $HOME/cmd/go.py $TMP_FILE $HOME/cmd/go.list
if [ -e $TMP_FILE ]
then
NEW_DIR=`cat $TMP_FILE`
#echo $NEW_DIR
builtin cd $NEW_DIR 2>/dev/null && pwd
rm $TMP_FILE
fi
별 것은 없고 python 파일 실행하고 결과를 받아서 이동하는 코드다.
실행은 .bashrc에 아래와 같이 추가하여 사용한다. 다들 알겠지만 .bashrc 파일은 home 디렉터리에 있고 이름은 원하는 것으로 변경하면 된다.
alias g='. $HOME/cmd/go.sh'
go.list 파일에는 디렉터리 정보가 들어 있는데 아래와 같이 구성한다.
"1", "/tmp/1"
"2", "/tmp/2"
"3", "/tmp/3"
"4", "/tmp/4"
"5", "/tmp/5"
"6", "/tmp/6"
"7", "/tmp/7"
"8", "/tmp/8"
"9", "/tmp/9"
"a", "/tmp/a"
"b", "/tmp/b"
"c", "/tmp/c"
"d", "/tmp/d"
"v", "/tmp/v"
참고로... go.sh, go.py, go.list 는 같은 디렉터리에 있어야 함.
이렇게 하고 실행하면 된다.
go.py 전체 소스
#!/usr/bin/env python2
# -*- coding: UTF-8 -*-
#kate: syntax Python ;
import os
import sys
import subprocess
'''function 1 on F1 1 and NUM-1'''
global file_path
global list_file
def moveTo(where):
os.system("echo \"" + golist_strings[where-1][1] + "\" > " + file_path)
sys.exit()
return "move to " + golist_strings[where-1][1] + " " + str(where)
import sys,os
import curses
global menuE
global e
global keychar
global golist_strings
e = 0
menuE = 1 # active entry
keychar = " " # like 1 or 2 ...
max_line_length = 0
go_list_off = 0
display_per_page = 10
class switch(object):
value = None
def __new__(class_, value):
class_.value = value
return True
def case(*args):
return any((arg == switch.value for arg in args))
def draw_menu(stdscr):
global menuE
global e
global keychar
global max_line_length
global go_list_off
k = 0
cursor_x = 0
cursor_y = 0
# Clear and refresh the screen for a blank canvas
stdscr.clear()
stdscr.refresh()
# Start colors in curses
curses.start_color()
curses.init_pair(1, curses.COLOR_CYAN, curses.COLOR_BLACK)
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK)
curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE)
# Loop where k is the last character pressed
while (k != ord('q')):
# Initialization
stdscr.clear()
height, width = stdscr.getmaxyx()
ki = int(k)
try: keychar = chr(k)
except: keychar = 0
callfunc = False
while switch(k):
if case(10, 32 , 83): # SPACE , ENTER , 83 mouse middle
callfunc = True
break
pass
break
if callfunc:
e = moveTo(menuE)
if k == curses.KEY_DOWN:
if menuE < golist_cnt :
cursor_y = cursor_y + 1
menuE = menuE + 1
elif k == curses.KEY_UP:
if menuE > 1 :
cursor_y = cursor_y - 1
menuE = menuE - 1
cursor_x = max(0, cursor_x)
cursor_x = min(width-1, cursor_x)
cursor_y = max(0, cursor_y)
cursor_y = min(height-1, cursor_y)
# Declaration of strings
title = "Choose where you want to go."[:width-1]
statusbarstr = "Press 'q' to exit"
# Centering calculations
start_x_title = int(( width // 2) - (len(title) // 2) - len(title) % 2)
start_x_subtitle = int(( width // 2) - (max_line_length // 2) - max_line_length % 2)
start_y = int(( height // 2) - (offset_y // 2) - (offset_y % 2)) - 1
# Rendering some text
#whstr = "Width: {}, Height: {} {}".format(width, height, menuE)
#stdscr.addstr(0, 0, whstr, curses.color_pair(1))
# Render status bar
stdscr.attron(curses.color_pair(3))
stdscr.addstr(height-1, 0, statusbarstr)
stdscr.addstr(height-1, len(statusbarstr), " " * (width - len(statusbarstr) - 1))
stdscr.attroff(curses.color_pair(3))
# Turning on attributes for title
stdscr.attron(curses.color_pair(2))
stdscr.attron(curses.A_BOLD)
# Rendering title
stdscr.addstr(start_y, start_x_title, title)
# Turning off attributes for title
stdscr.attroff(curses.color_pair(2))
stdscr.attroff(curses.A_BOLD)
if display_per_page < menuE :
go_list_off = menuE - display_per_page
name_idx = 0
display_offset = 0;
for (name, path) in golist_strings:
name_idx = name_idx + 1
if go_list_off > name_idx :
continue
if display_offset > display_per_page :
break
display_offset = display_offset + 1
if name_idx == menuE :
stdscr.attron(curses.color_pair(3))
stdscr.attron( curses.A_BOLD)
else :
stdscr.attroff(curses.color_pair(3))
stdscr.attroff(curses.A_BOLD)
stdscr.addstr(start_y + 1 + display_offset, start_x_subtitle, name + " - " + path)
# Refresh the screen
stdscr.refresh()
# Wait for next input
k = stdscr.getch()
def main():
global file_path
global golist_strings
global golist_cnt
global max_line_length
global offset_y
global list_file
file_path = sys.argv[1]
list_file = sys.argv[2]
with open(list_file) as f:
global golist_strings
golist_strings = [tuple(map(lambda str:str.replace('\"', '').strip(), i.split(','))) for i in f]
golist_cnt = len(golist_strings)
max = 3
for go in golist_strings :
len_go = len(go[0]) + len(go[1]) + 3;
if (len_go > max) :
max = len_go
max_line_length = max
offset_y = 2 + display_per_page;
curses.wrapper(draw_menu)
if __name__ == "__main__":
main()
'놀기 > Linux' 카테고리의 다른 글
SSH 설치하기 (Ubuntu 20.04) (0) | 2022.01.14 |
---|---|
Ubuntu 접속 기록 삭제, 명령어 히스토리 삭제하기 (0) | 2021.10.27 |
시리얼 통신 프로그램 추천 (minicom / moserial / gtkterm, ubuntu 20.04 기준) (0) | 2021.07.25 |
OneDrive service 끄기 (0) | 2021.07.09 |
Ubuntu 20.04 에 Microsoft OneDrive 설치 (초보 전용) (1) | 2021.07.06 |
댓글