我有以下命令:
files=$(ls -lhrt dirname) && echo $files | head -5 && echo $files | tail -5
这个想法是返回目录中最旧和最新的 5 个文件dirname
。这将返回请求的数据 - 但是,这些行混杂在一起。
有没有办法更好地格式化输出?(或者也许是编写此功能的更好方法)?
始终引用变量扩展以防止单词拆分和通解。当您离开$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"
头尾
巴(不必将先前命令的全部输出存储到一个变量中)
注意:按照这个,我将使用前 4 行和最后 4 行作为使用seq 1 100..
的样本,但前 5 行和最后 5 行用于使用ls -lhrt dirname
的样本。
第一种方式,连续使用head
和tail
如果您尝试:
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
给出错误的答案。
这是由于缓冲,但 bash 允许您使用无缓冲输入:
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
必须完成这项工作。
甚至,如果你想玩bash和一个大变量:
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 sed
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;'
像这样添加换行符怎么样:
files=$(ls -lhrt dirname) && echo -e "${files}n" | head -5 && echo -e "${files}n" | tail -5
解释:
-e
标志使 echo 能够解释转义,例如本示例中的转义n
。
n
本身就是"新行"的转义序列。因此,它所做的只是在回显变量之后添加一个新行。
${ }
称为支撑扩展。由于我将字符串放在引号中,因此${}
会将变量扩展到字符串。
即使它被请求用于 BASH,我只是在这里放了 ZSH 行
echo dirname/*(.om[1,5]) dirname/*(.om[-5,-1])
这将返回包含 5 个最旧文件和 5 个最新文件的files
列表(基于修改时间)。其他基于ls -lrth
的解决方案可能会返回目录、链接、管道或其他任何内容。
你可以用任何东西替换echo
,但是你要求一种查找文件的方法,因此ZSH中的正确答案是上面的glob(没有echo
)
它的工作原理是这样的:
dirname/*
:取所有数学字符串(
: 开球说明符.
:仅返回普通文件om
:根据修改时间排序[1,5]
返回前五个或[-5,-1]
返回后五个)
: 关闭全局说明符
更多关于 zsh 通配的信息可以在这里找到: http://www.bash2zsh.com/zsh_refcard/refcard.pdf