自动完成最新文件

自动完成最新文件

我有一个创建文本文件的过程,其文件名基于创建时刻的时间戳:

$ ls
1378971222.txt
1378971254.txt
1378971482.txt
1378971488.txt
1378972089.txt
1378972140.txt
1378972141.txt
1378972153.txt
1378972155.txt
1378972241.txt

我如何自动完成最新创建的文件的文件名,即具有最新 mtime 的文件?无法对这些文件使用制表符补全,因为文件名中的几乎每个字符都与另一个文件共享。我希望找到一个快捷方式(例如Alt .自动完成最后一个命令的最后一个参数)。我已经设法编造了以下别名,该别名非常适合,但我很想知道是否存在可以与、和其他应用程序VIM一起使用的通用快捷方式。kde-opensqlite3

alias lastest="vim `ls -t | grep -vE "^total [0-9]*$" | head -n1`"

答案1

你可以轻松配置它zsh,例如这样的东西:

zstyle ':completion:*' file-sort date

(您还可以更改该行,使该样式仅用于某些文件名模式)

zsh与 bash 非常相似,您可以将其称为 bash 的超集 - 功能/用法方面。

但也许 bash 也有类似的功能。

答案2

vim只需从别名中删除即可。做这样的事情:

alias latest='ls -tr | tail -n 1'

然后您可以使用任何程序打开最新的文件:

emacs `latest`
ls `latest`
mv `latest` ../

ETC。

但是,如果您的文件名包含空格或奇怪的字符,这将会中断,这就是您的原因永远不应该解析ls。更好的方法是这样的(将其添加到您的.bashrc):

function latest(){
  $1 "$(find . -type f -printf "%C@ %p\n" | sort | tail -n 1 | cut -d " " -f 2-)"
}

该函数将执行您作为参数提供的任何命令,并将调用结果find(最新文件)传递给该命令。因此,您可以执行以下操作:

latest emacs
latest less

如果您需要能够做类似的事情,mv $(latest) foo/请尝试以下操作:

function latest(){
   A=(${@})
   prog=$1;
   lat=$(find . -type f -printf "%C@ %p\n" | sort | tail -n 1 | cut -d " " -f 2-)
   if [ ! -z $2 ] ; then 
     args=${A[@]:1}; 
     $prog "$lat" "${A[@]:1}"
   else
     $prog "$lat"
   fi
}

然后,要将最新文件复制到bar/,您可以这样做

latest cp bar

而且你仍然可以latest emacs像以前一样做。

答案3

修改 bash 补全“_filedir”函数以允许使用最后一个文件名进行制表符补全。这是一个可以source执行此操作的脚本:

#!/bin/sh

_filedir_newest()
{
    local parent="$1"
    if [ "${#parent}" -gt "0" ]; then
        parent="$(compgen -d -- ${1:0:-1})/"
    fi
    newest=$(bash -c "ls -tr $parent | tail -n 1")
    echo "$parent$newest"
} # _filedir_newest()

_filedir()
{
    local IFS=$'\n'

    _tilde "$cur" || return

    local -a toks
    local x reset
    local newest=0

    reset=$(shopt -po noglob); set -o noglob
    toks=( $(compgen -d -- "$cur") )
    IFS=' '; $reset; IFS=$'\n'

    if [[ "$1" != -d ]]; then
        local quoted
        if [[ "$cur" = "?" ]] || [[ "${cur: -2}" = "/?" ]]; then
            cur="${cur:0:-1}"
            newest=1
        fi
        _quote_readline_by_ref "$cur" quoted

        # Munge xspec to contain uppercase version too
        # http://thread.gmane.org/gmane.comp.shells.bash.bugs/15294/focus=15306
        local xspec=${1:+"!*.@($1|${1^^})"}
        reset=$(shopt -po noglob); set -o noglob
        toks+=( $(compgen -f -X "$xspec" -- $quoted) )
        IFS=' '; $reset; IFS=$'\n'

        # Try without filter if it failed to produce anything and configured to
        [[ -n ${COMP_FILEDIR_FALLBACK:-} && -n "$1" && ${#toks[@]} -lt 1 ]] && {
            reset=$(shopt -po noglob); set -o noglob
            toks+=( $(compgen -f -- $quoted) )
            IFS=' '; $reset; IFS=$'\n'
        }
    fi

    if [[ ${#toks[@]} -ne 0 ]]; then
        # 2>/dev/null for direct invocation, e.g. in the _filedir unit test
        compopt -o filenames 2>/dev/null
        if [[ $newest -eq 1 ]]; then
            COMPREPLY+=( $(_filedir_newest "$cur") )
        else
            COMPREPLY+=( "${toks[@]}" )
        fi
    fi
} # _filedir()

_filedir_xspec()
{
    local cur prev words cword
    _init_completion || return

    _tilde "$cur" || return

    local IFS=$'\n' xspec=${_xspecs[${1##*/}]} tmp
    local -a toks
    local newest=0

    if [[ "$cur" = "?" ]] || [[ "${cur: -2}" = "/?" ]]; then
        cur="${cur:0:-1}"
        newest=1
    fi

    toks=( $(
        compgen -d -- "$(quote_readline "$cur")" | {
        while read -r tmp; do
            printf '%s\n' $tmp
        done
        }
        ))

    # Munge xspec to contain uppercase version too
    # http://thread.gmane.org/gmane.comp.shells.bash.bugs/15294/focus=15306
    eval xspec="${xspec}"
    local matchop=!
    if [[ $xspec == !* ]]; then
        xspec=${xspec#!}
        matchop=@
    fi
    xspec="$matchop($xspec|${xspec^^})"

    toks+=( $(
        eval compgen -f -X "'!$xspec'" -- "\$(quote_readline "\$cur")" | {
        while read -r tmp; do
            [[ -n $tmp ]] && printf '%s\n' $tmp
        done
        }
        ))

    if [[ ${#toks[@]} -ne 0 ]]; then
        compopt -o filenames
        if [[ $newest -eq 1 ]]; then
            COMPREPLY=( $(_filedir_newest "$cur") )
        else
            COMPREPLY=( "${toks[@]}" )
        fi
    fi
} # _filedir_xspec()

可以将其添加到您的~/.bashrc像这样(/path/to/the/script适当替换),以便它适用于所有 bash 会话:

source /path/to/the/script/_filedir.sh

安装后,“?”用作目录中最后一个文件的特殊指示符,例如:

eog ~/Downloads/?<TAB>

变成(在一种情况下):

eog ~/Downloads/Sunscreen\ Permission\ -\ ToddlerPrimaryElementary.pdf

该技术适用于任何目录,因为它与 bash 完成系统集成,而不仅仅是报告当前目录中的最新文件。我经常使用此功能将最近下载的文件从浏览器移动到我正在积极处理的任何项目的文件夹中 ( mv ~/Downloads/?<TAB> .)。

更新于 2021 年 10 月 27 日:_filedir_xspec现在也 适用于bash 自动完成例程更新于2021年11月9日:修复了上次更新后对当前目录进行操作时的错误。

答案4

问题的背景是使用速度。我发现键盘宏最合适。添加~/.inputrc

# Alt-L --> newest file in directory
"\el": "$(ls -t|head -1)"

进一步的想法:最初,我想要一些能给我第一个、第二个、第三个最新文件的东西。一个想法是,用标记标记这些位置,例如“grep x _”,然后执行键盘宏“\C-alatest-expansion \Cm”,“latest-expansion”会提示一个curses-selection列表以供选择命令行中每个“_”标记的最新文件。

我认为这是一个重要的问题,因为 GUI 相对于 SHELL 的另一个优势是对我来说可以选择最近使用/创建的文件和目录。autojump对目录有一点帮助,但缺少文件的解决方案。

相关内容