変更日付で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.'
}
作成時にリストを並べ替えると、はるかに簡単です 。でもできないなら…
古典的なアプローチは、データにソート基準を追加し、それをソートして、追加された残骸を削除することです。タイムスタンプとファイル名を含む配列を、明確な方法で、辞書順にソートできる形式のタイムスタンプで構築します。配列を並べ替え(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が基本オペレーティングシステムの一部でない場合は、 stat
をgstat
に、sort
をgsort
に、cut
をgcut
に変更する必要があります。
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以降が必要です)。
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固有であるためです)。