web-dev-qa-db-ja.com

変更日付でzsh配列を並べ替える方法は?

変更日付でzsh配列を並べ替える方法は?

files=( ~/a ~/b ~/c )
# how to sort files by date?

PS:これが私の正確なユースケースです(fzはほぼfzf

v () {
 local files
 files=() 
 command rg '^>' ~/.viminfo | cut -c3- | while read line
 do
  [ -f "${line/\~/$HOME}" ] && files+="$line" 
 done
 test -f ~/.emacs.d/.cache/recentf && {
  command rg --only-matching --replace '$1' '^\s*"(.*)"$' ~/.emacs.d/.cache/recentf | while read line
  do
   [ -f "$line" ] && files+="$line" 
  done
 }
 files="$(<<<"${(F)files}" fz --print0 --query "$*")"  || return 1
 files="${files//\~/$HOME}" 
 local ve="$ve" 
 test -z "$ve" && ! isSSH && ve=nvim 
 "${ve:-vim}" -p ${(0@)files}
 : '-o opens in split view, -p in tabs. Use gt, gT, <num>gt to navigate tabs.'
}
2
HappyFace

作成時にリストを並べ替えると、はるかに簡単です 。でもできないなら…

古典的なアプローチは、データにソート基準を追加し、それをソートして、追加された残骸を削除することです。タイムスタンプとファイル名を含む配列を、明確な方法で、辞書順にソートできる形式のタイムスタンプで構築します。配列を並べ替え(oパラメータ展開フラグ を使用)、次にプレフィックスを削除します。 stat モジュールを使用して、ファイルの変更時刻を取得できます。

zmodload zsh/stat
for ((i=1; i<$#files; i++)); do times[$i]=$(stat -g -F %020s%N +mtime -L -- $files[$i]):$files[$i]; done
sorted=(${${(o)times}#*:})

Zstatへの%N形式(ナノ秒の解像度でタイムスタンプを取得するため)には、zsh≥5.6が必要です。 zshが古い場合、それを削除するとコードは機能しますが、タイムスタンプを1秒の解像度で比較します。多くのファイルシステムは1秒未満の解像度を持っていますが、古いバージョンのzshのzsh statモジュールでそれを取得できるとは思いません。

Zshが古すぎる場合は、statユーティリティを使用して、より正確なタイムスタンプを GNU coreutils から取得できます。あなたがそれを持っているなら、おそらく他にもGNU coreutilsがあるので、それらを使用します。GNU coreutilsは通常、非組み込みLinuxに存在します、ただしBSDまたはmacOSにはない場合があります。macOSでは、brewを使用してインストールできます。GNU coreutilsが基本オペレーティングシステムの一部でない場合は、 statgstatに、sortgsortに、cutgcutに変更する必要があります。

if (($#files)); then
  sorted=(${(0@)"$(stat  --printf='%040.18Y:%n\0' "$files[@]" | sort -rz | cut -z -d':' -f2-)"})
else
  sorted=()
fi

代替のzshアプローチは、$filesなどのすべてのファイルを含むパターンを構築することです。このパターンに一致するファイルを並べ替えてから、必要なファイルのみを含めるようにフィルタリングします。 more_filesのパターン全体を作成する必要がありますが、常に実用的であるとは限りません。

more_files=(~/*(Om))
sorted=(${more_files:*files})

あの に似たアプローチを使うことができます:

zmodload zsh/stat

array=(file1 file2...)

# store mtimes in an associative array:
typeset -A mtime
stat -nLF %s.%N -A mtime +mtime -- $array

# sort using the Oe glob qualifier
sorted_array=(/(e['reply=($array)']nOe['REPLY=$mtime[$REPLY]'])

%Nナノ秒の場合、zsh 5.6以降が必要です)。

3

Jeffが指摘したように、次のようにソートされた配列を作成する方が簡単です。

_set -A files $(ls -trd -- ~/a ~/b ~/c)
_

ここで、lsの出力を_$IFS_文字に分割します(デフォルトではSPC、TAB、LFおよびNULを含みます)。LFのみ(SPCまたはTAB文字を含むよりもファイル名で作業できるようにするため(ただしLF明らかに)は不可))、_IFS=$'\n'_を設定するか、fパラメータ展開フラグ:

_files=(${(f)"$(ls -trd -- $files)"})
_

(ここでも、ksh88スタイルの_set -A array ..._の代わりにzshスタイルのarray=(...)構文を使用しています。これは、この構文はすでにzsh固有であるためです)。

2
Gerard H. Pille