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

1つの変更点:

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

おすすめ記事