Midnight Commander(MC), User Menu 사용법.

준비운동을 마치고 본격 사용에 돌입했다. 이걸 몇 년전에 고민했었다면 좀 더 편안한 생활을 할 수 있었을 텐데..
역시, 무식하면 몸이 고생.

다음 글에서 영감(?)을 얻었다.


하고 싶은 건 이렇다.
특정 디렉토리에서 특정 디렉토리로 파일을 복사하고 싶다. 실수를 방지하기 위해, 이 상황일 때만 메뉴가 발동(?)되면 좋겠고, 복사 후에는 소유권도 살짝 변경해야 한다.

지금까지는 이 작업(들)을 모두 수동으로 해왔다. cp 를 하고, chmod 를 해주는.

하지만, 오늘부터 내 삶은 달라졌다. (이 정도로..?)
cp 대신 진행 상황을 보기 위해 rsync 를 사용하고, 강력한 도구 MC 의 힘을 빌린다. (Mr. Norton, 보고 계십니까? 들리십니까? 당신의 유산이 이렇게 살아 남아있습니다.)

자..

순서를 정리해보면,

  • MC 에서 한쪽은 원본창, 다른 한쪽은 복사본창으로 설정한다.
  • 위 창들은 특정 디렉토리 하에 있기에, 그 양쪽 모두 그 디렉토리가 선택되었을 경우에만 메뉴가 나와야 한다.
  • 한쪽에서 파일(또는 디렉토리)을 선택(tag)할 수도 있고, 단일 파일만 원할 경우도 있다.
  • 선택을 했을 경우(tagged), 명령이 실행되고 난 뒤 선택이 풀리기(untagged)를 원한다.

이걸 어떻게 MC 에 적용할 수 있을까?

MC 에는 User Menu 라는 기능이 있다. 사용자가 원하는 명령을 입력했다가, F2 를 호출하여 사용할 수 있다. 사용자 메뉴에 명령을 추가하기 위해선 ‘menu’ 파일을 편집해야 한다.
이 파일의 위치는 다음과 같다.

  • /etc/mc/mc.menu
  • 현재 디렉토리의 .mc.menu
  • ~/.config/mc/menu

/etc/mc/mc.menu 가 기본값이고, ‘사용자’라는 이름이 붙으려면, 현재 디렉토리에 .mc.menu 가 존재하거나, 또는 ~/.config/mc/menu 를 생성해야 한다.
우분투 Man Page 에는 기본 파일이 /usr/share/mc/mc.menu 라고 나와있지만, 적어도 18.04 에는 저런 파일은 없다.

디렉토리에 .mc.menu 를 넣는 방식이 경우에 따라선 꽤 확실한 효과를 볼 수 있다고 생각한다. 그 디렉토리에서만 필요한 작업이 있는 경우엔 각종 if 를 남발하지 않고도 쉽게 작업을 할 수 있겠다.

여기선 보다 범용으로, ~/.config/mc/menu 를 사용해본다.

shell_patterns=0

=+ t t & d ^\/opt\/abcd\/.* & D ^\/Storage\/?.*
c	파일 복사 후 소유권 변환 (선택)
	rsync -ah --chown=usera:groupb --info=progress2 %u %D

# 위와 동일하지만, 선택되지 않은 경우에 이 메뉴가 나오게 한다.
=+ ! t t & d ^\/opt\/abcd\/.* & D ^\/Storage\/?.*
c	파일 복사 후 소유권 변환 (단일)
	rsync -ah --chown=usera:groupb --info=progress2 %f %D

shell_pattern=0 은, 앞으로 나올 조건에서 Regex 를 사용하겠다는 뜻이다. 1 을 쓰면 일반 와일드카드를 사용한다.

= 와 + 는 이전 글에서 언급했으므로 넘어간다.
둘을 같이 써줘야, 메뉴에도 표시되게끔 하고, 그 메뉴를 기본으로 선택하게끔 할 수 있다.

문제는 그 다음에 나오는 다소 복잡해보이는 조건식이다.

t t 는, 현재 커서가 위치한 곳의 파일/디렉토리 typetagged, 즉 선택이 되어있는지를 확인한다. 즉, Ins. 키를 눌러서 파일들이 선택된 상태인지, 아니면 그냥 단일 파일인지를 확인한다.

! t t 는, 선택되지 않은 상태, 즉 단일 파일 상태임을 뜻한다.

Man Page DefaultConditions 항목에서 보다 상세한 사항을 확인하라.

그 뒤 복잡해보이는 Regex 는 별게 없는데, Escaping 을 위해 \ 를 넣어서 쉽게 읽히질 않아서 그럴 뿐이다. \ 를 빼고본다면,

d ^/opt/abcd/.* & D ^/Storage/?.*

d 는, 현재 커서가 위치한 패널의 디렉토리를 의미한다. ^/opt/abcd/.* 이므로, 그 디렉토리가 /opt/abcd 산하에 있는지를 확인한다.
D 는 반대편 패널의 디렉토리다. 여기가 /Storage 산하인지를 확인한다.

종합하여, 단일/복수 파일인지, 현재 디렉토리가 /opt/abcd 산하 이고, 반대편 디렉토리가 /Storage 산하인지를 확인하고, 맞을 경우에만 메뉴를 표시한다.
이렇게 조건을 줄 수 있으므로, 오작동이 발생할 가능성을 낮출 수 있다.

디렉토리 조건이 보다 복잡하고, 제한된 상황에서만 사용한다면, 위에서 언급한 대로 그 디렉토리에 .mc.menu 를 만들어놓는 편이 더 나을 수도 있겠다.

조건이 맞았으니 이젠 명령을 실행할 차례다. 그 전에, 이 메뉴 이름을 넣어야 하는데, 그게 바로 ‘c 파일 복사 후 소유권 변환 (선택)’ 이다.
첫번째 문자는 단축키 역할을 하고, 두번째는 메뉴명이 되겠다.
t t 의 경우와 ! t t 모두 c 로 단축키가 같은데, 이 둘은 상호배타관계로, 동시에 메뉴에 표시될 일이 없기에 같은 키를 할당해도 아무런 문제가 없다.

그 다음, 실제 실행명령을 넣어야 한다. 그에 앞서 /etc/mc/mc.menu 를 먼저 확인해봐야 한다.

+ ! t t
@       Do something on the current file
        CMD=%{Enter command}
        $CMD %f

+ t t
@       Do something on the tagged files
        CMD=%{Enter command}
        for i in %t ; do
            $CMD "$i"
        done

t t 일때는 for 를 사용해서 %t(tagged files) 로 받은 인수들을 나누어 하나씩 명령을 실행하고 있다. 대부분은 이렇게 하는 게 맞다. 하지만, 내가 사용할 rsync 는 꼭 이렇게 하지 않아도 된다.
rsync 는 앞에 있는 모든 인수를 원본(Source)로 받아들이고, 맨 끝 인수를 복사본(Destination)으로 인식한다. 따라서,

rsync a b c d e f g

이 명령은, a b c d e f 를 g 로 복사하라는 명령이 되겠다. rsync 는 충분히 똑똑하기에, 만약 g 가 존재하지 않으면 g 를 디렉토리로 생성하고 파일들을 복사해넣는다.

이런 이유로 rsync 를 사용한다면 굳이 for 를 사용하는 세심함을 보이지 않아도 된다.

그리하여, 이런 두가지 명령이 나왔다.

# 복수 파일 복사
rsync -ah --chown=usera:groupb --info=progress2 %u %D

# 단일 파일 복사
rsync -ah --chown=usera:groupb --info=progress2 %f %D

다른 부분은 %u 와 %f 뿐이다.
%D 는 반대편 디렉토리를 뜻한다.

자세한 설명은 /etc/mc/mc.menu 를 참고하고, 간단히 정리하면 아래와 같다.

  • %f : 파일명. (네트웍일 경우는 주소포함. 로컬일 경우는 파일명만)
  • %p : 어떤 경우든 파일명만. (경로는 포함하지 않음.)
  • %s : 선택된 파일. 또는, 선택이 없을 경우 현재 파일(명).
  • %t : 선택된 파일.
  • %u : %t 와 같지만, 명령이 끝나면 선택을 해제한다.
  • %d : 현재 패널의 경로명.
  • 대문자로 쓸 경우, 반대편 패널을 뜻한다.

그리하여.. 정리하자면, 단일 파일일 경우는 현재 커서가 위치한 곳에 있는 파일(%f) 를 다른쪽 패널 디렉토리로 복사하라는 명령이 된다.

두번째, 선택이 있었을 경우는 %u 를 사용해서, 선택한 파일들(%u)을 다른 패널 디렉토리(%D)로 복사하고, 복사가 끝나면 선택을 해제하라(%u)가 된다.

참고로, 원본 파일을 넣어줄 때 경로를 포함하지 않고 그냥 파일명(%f)만 넘겨도 되는 이유는 뭘까?
그 경로에서 명령이 실행되기 때문에 경로가 불필요하다.

즉,

$ usera@trueblue:/opt/abcd$ rsync sourcefile.txt /Storage/test2

/opt/abcd/sourcefile.txt 를 복사하려고 한다면, 위와 같은 상태에서 명령이 실행되기 때문에, 굳이 경로를 명시해줄 필요가 없다. MC 로 저 명령을 실행하려면, 늘 그 경로로 이동을 해 있어야만 하므로.

그럼에도 불구하고 경로를 꼭 넣어야만 한다면.. 아마도 %d”/”%p 면 되지 않을까?
이 부분은 해보지 않아서..

이걸로, 오랫동안 끌어오던 해묵은 숙제하나를 끝냈다.
앞으로 Linux/macOS 생활은 좀 더 편해질 수 있겠지.

Double Commander 로도 이 비슷한 상황을 헤쳐나갔었는데, 둘 다 일장일단이 있는 듯 하다. 다만, DC 에는 이렇게 디렉토리 조건을 주는 게 가능한지는 모르겠다. 전에도 찾다가 못찾았던 듯 한데?

안녕하세요. 글 남겨주셔서 고맙습니다.