zsh 완료: tar를 사용하여 아카이브를 추출할 때 디렉토리가 제공되지 않습니다.

zsh 완료: tar를 사용하여 아카이브를 추출할 때 디렉토리가 제공되지 않습니다.

명령 완성 시스템은 tar매우 영리합니다. 다양한 아카이브 유형이 있는 경우 사용된 tar 옵션을 기반으로 관련 파일을 제공합니다.

$ ls
file.tar.xz
file.tar.gz

$ tar xJf f<TAB>
file.tar.xz

$ tar xzf f<TAB>
file.tar.gz

파일 xJf에 대한 작업을 인식 하고 파일에 대한 작업을 수행합니다.tar.xzxzftar.gz

그러나 디렉토리가 현재 위치에 존재할 때 완료를 위해 제공하기도 합니다.

$ tar xJf f<TAB>
foo/   file.tar.xz

아카이브를 추출할 때만 파일이 완성되기를 원한다고 완성 시스템에 알릴 수 있습니까(예: tar옵션 x...)?

하지만 아카이브를 생성할 때 여전히 디렉터리( tar옵션 )를 제공해야 합니다 c....

tar cpJf foo.tar.xz 

내 생각에는 tar명령의 기본 완성 파일 인 /usr/share/zsh/functions/Completion/Unix/_tar. 하지만 어떻게?

답변1

완성 시스템에 다음 파일만 표시되도록 설정모든호출은 tar비교적 간단합니다. zstyle이 명령을 추가하면 .zshrc 문제가 해결됩니다.

zstyle ':completion:*:*:tar:*' 'file-patterns' '*(.)'

이는 내장 함수의 코드를 트리거하여 _filesglob 한정자를 통해 일반 파일과 일치하는 파일 패턴을 제한합니다 (.).

불행하게도 호출된 모든 패턴 일치 항목을 덮어쓰므 tar로 예제의 확장자 기반 일치는 더 이상 작동하지 않으며 아카이브를 생성할 때 디렉터리는 일치 항목의 일부가 아닙니다. 보다 선택적으로 디렉토리를 무시하도록 변경하려면 zsh완성 코드를 더 자세히 살펴보아야 합니다.


함수를 수정하여 이를 달성 할 수 있습니다 _tar_archive(방법을 지적한 @Gilles에게 감사드립니다). 이 기능은 이미 아카이브 추출과 아카이브 생성을 위한 별도의 처리를 수행하므로 아카이브 추출에 사용되는 라인만 변경하면 됩니다.

이것은 내 시스템(macOS 10.15, zsh 5.7.1)의 코드를 기반으로 수정된 코드입니다. 추출의 경우 직접 호출 되므로 _path_files파일만 살펴봅니다. 원본 코드는 를 사용하며 _files파일과 디렉터리를 반복합니다.

#autoload

# This is used to generate filenames usable as a tar archive.  This may
# get one argument, a collection of tar option characters that may be
# used to find out what kind of filename is needed.  If no argument is
# given but the parameter `_tar_cmd' is set, that is used.
# If your version of `tar' supports this you may want to complete
# things like `host:file' or `user@host:file' here.

local expl

[[ $# -eq 0 && $+_tar_cmd -ne 0 ]] && set "$_tar_cmd"

_description files expl 'archive file'

if [[ "$1" = *[urtx]* ]]; then
  if [[ "$1" = *[zZ]* ]]; then
    _path_files "$expl[@]" -g '*.((tar|TAR).(gz|GZ|Z)|tgz)(-.)'
  elif [[ "$1" = *[Ijy]* ]]; then
    _path_files "$expl[@]" -g '*.(tar|TAR).bz2(-.)'
  elif [[ "$1" = *J* ]]; then
    _path_files "$expl[@]" -g '*.(tar|TAR).(lzma|xz)(-.)'
  elif [[ "$_cmd_variant[$service]" == (gnu|libarchive) ]]; then
    _path_files "$expl[@]" -g '*.((tar|TAR)(.gz|.GZ|.Z|.bz2|.lzma|.xz|)|(tbz|tgz|txz))(-.)'
  else
    _path_files "$expl[@]" -g '*.(tar|TAR)(-.)'
  fi
else
  _files "$expl[@]"
fi

완성 시스템 내에서 기능을 수정하는 것은 약간 까다로울 수 있습니다. 원래 디렉터리에 게시된 코드를 변경하는 것보다 복사본을 만드는 것이 더 좋습니다. 빠른 참조를 위해 다음은 내 시스템에 필요한 명령입니다. 다른 시스템의 요구 사항은 다를 수 있습니다. 이 Stack Exchange 답변에는 자세한 내용이 있습니다. https://unix.stackexchange.com/a/33898/432774

한 가지 변경사항:

mkdir ~/.zfunc
for d in $fpath; do
  [[ -f $d/_tar_archive ]] && cp $d/_tar_archive ~/.zfunc; break
done
# (edit file as noted above)

print 'fpath=( ~/.zfunc "${fpath[@]}" )' >> ~/.zshrc
# (restart shell)

이러한 명령은 코드가 변경될 때마다 필요합니다. 단순히 셸을 다시 시작하는 것만으로는 충분하지 않을 수 있습니다.

unfunction _tar_archive
autoload -Uz _tar_archive

rm ~/.zcompdump
rm ~/.zcompcache/*
compinit

관련 정보