一行bash命令,用于查找目录中N个最旧和最新的文件

时间:2017-11-17 12:09:16

标签: bash

我有以下命令:

files=$(ls -lhrt dirname) && echo $files | head -5 && echo $files | tail -5

我们的想法是在目录dirname中返回最旧和最新的5个文件。这将返回请求的数据 - 但是,这些行混杂在一起。

有没有办法更好地格式化输出? (或者也许是编写此功能的更好方法)?

4 个答案:

答案 0 :(得分:2)

始终引用变量扩展以防止单词拆分和通配。当你离开$files不带引号的bash时,单词拆分传递会导致换行丢失。

files=$(ls -lhrt dirname) && echo "$files" | head -5 && echo "$files" | tail -5

使用&&运算符没有任何实际好处。我只想写:

files=$(ls -lhrt dirname)
echo "$files" | head -5
echo "$files" | tail -5

或者,更好的是,将echo交换为<<<以避免不必要的子流程。

files=$(ls -lhrt dirname)
head -5 <<< "$files"
tail -5 <<< "$files"

答案 1 :(得分:2)

一起尾巴

(无需将前一个命令的整个输出存储到一个变量中)

Nota:沿着这个,我将使用前4行和最后4行使用seq 1 100..进行采样,但使用ls -lhrt dirname进行采样的前5行和后5行。

首先,连续使用headtail

如果您尝试:

seq 1 100000 | (head -n 4;tail -n 4;)
1
2
3
4
99997
99998
99999
100000

似乎可以胜任,但

seq 1 1000 | (head -n 4;tail -n 4;)
1
2
3
4

给出错误答案。

这是由于缓冲,但是允许您使用无缓冲的输入:

seq 1 12 | { for i in {1..4};do read foo;echo "$foo";done;tail -n 4 ;}
1
2
3
4
9
10
11
12

最后

根据您的要求,试试这个:

{ for i in {1..5};do read foo;echo "$foo";done;tail -n 5;} < <(ls -lhrt dirname) 

必须符合您的需要。

或者在tee

的帮助下将两者结合使用

看看:

seq 1 12 | tee > >(tail -n4) >(head -n4)
1
2
3
4
9
10
11
12

但这可能会在终端上呈现奇怪的东西,为了防止这种情况,您可以将整个管道传输到cat

seq 1 12 | tee > >(tail -n4) >(head -n4) | cat
1
2
3
4
9
10
11
12

因此

ls -lhrt dirname | tee > >(tail -n5) >(head -n5) | cat

必须做好这份工作。

甚至,如果你想玩和一个大变量:

files=$(seq 1 12) out='' in=''
for i in {1..4};do
    in+=${files%%$'\n'*}$'\n'
    files=${files#*$'\n'}
    out=${files##*$'\n'}$'\n'${out}
    files=${files%$'\n'*}
done
echo "$in${out%$'\n'}"
1
2
3
4
9
10
11
12

然后再说:

files=$(ls -lhrt dirname) out='' in=''
for i in {1..5};do
    in+=${files%%$'\n'*}$'\n'
    files=${files#*$'\n'}
    out=${files##*$'\n'}$'\n'${out}
    files=${files%$'\n'*}
done
echo "$in${out%$'\n'}"

但您可以使用GNU

seq 1 100000 | sed -e ':a;N;4p;5,${s/^[^\n]*\n//;};$!ba;'
1
2
3
4
99997
99998
99999
100000

然后

ls -lhrt dirname | sed -e ':a;N;5p;6,${s/^[^\n]*\n//;};$!ba;'

答案 2 :(得分:1)

如何添加这样的换行符:

files=$(ls -lhrt dirname) && echo -e "${files}\n" | head -5 && echo -e "${files}\n" | tail -5

说明:

-e标志允许echo在此示例中解释转义符,例如\n

\n本身是“新行”的转义序列。所以它只是在echoed变量之后添加一个新行。

${ }被称为Brace Expansion。由于我将字符串放在引号中,${}会将变量扩展为字符串。

答案 3 :(得分:0)

即使它是BASH的要求,我也只是把ZSH线放在这里

echo dirname/*(.om[1,5]) dirname/*(.om[-5,-1])

这将返回files的列表,其中包含5个最旧和5个最新文件(基于修改时间)。基于ls -lrth的其他解决方案可能会返回目录或链接或管道或其他任何内容。

您可以用任何内容替换echo,但是您要求找到文件的方法,因此ZSH中的正确答案是上面的glob(没有echo

它的工作原理如下:

  • dirname/*:取所有数学字符串
  • (:open glob specifier
  • .:仅返回普通文件
  • om:根据修改时间对其进行排序
  • [1,5]返回前五位或[-5,-1]返回前五位
  • ):关闭glob说明符

有关zsh globbing的更多信息,请访问: http://www.bash2zsh.com/zsh_refcard/refcard.pdf