我需要在目录中找到最新文件。
我目前使用的行是:
cd /mypath/ && ls -t | head -n1
问题是,我一直在创建文件,有时,在'相同'的时间上创建了2个文件,这意味着当我执行上面的行我会错过其中一个文件。
有人可以帮忙吗?
对不起原始混音。这是一个简短的脚本,它将在目录中找到最新文件(作为第一个参数给出)。使用stat -c %Y
以自时代以来在几秒钟内找到其时间。然后与目录中的所有其他文件进行比较,如果时间差(td
)小于10
秒,请输出文件名(您可以调整差异以满足您的需求)
尝试一下:
#!/bin/bash
path="${1:-.}" ## set path (default .)
[ "${path:(-1):1}" = '/' ] && path="${path%/}" ## strip trailing '/'
oldifs="$IFS" ## save old IFS, set to break on newline
IFS=$'n'
fnarray=( $(ls -rt "$path" | tail -n5) ) ## read newest 5 into array
IFS="$oldifs"
for ((i=$((${#fnarray[@]} - 1)); i >= 0; i--)); do ## make sure newest is file
[ -f "${path}/${fnarray[i]}" ] && fn="${path}/${fnarray[i]}" && break
done
[ -d "$fn" ] && { echo "error: no file found in newest 5 entries"; exit 1; }
for i in "${path}"/*; do ## for each file in path
[ -f "$i" ] || continue ## if not a file skip
td=$(( $(stat -c %Y "$i") - $(stat -c %Y "$fn") )) ## time difference in sec
(( td < 0 )) && td=$(( td * -1 )) ## takes abs value
(( td < 10 )) && echo "$i" ## if less than 10 seconds, output file
done
exit 0
注意:我遇到的原始问题是由于目录中的最新条目是一个子目录(不需要)。由于ls ..| tail..
返回结果的方式,这提出了一个挑战。因此,基本上,我将最后5个作为黑客攻击(您应该设置5个初始尝试,如果fn
仍然是DIR,请增加两次,然后重试...直到您用尽了目录中的所有文件。或首先执行简单的find /path/ -type f
以确保存在一个文件) sigh ,但这会完全掩盖对最旧代码的测试。
我不喜欢解决方案的另一个问题是,比较stat
次在bash中的固有快速。因此,这不会在大型目录上快速闪电。(可使用&lt; 1000条目)。使用完全相同的时间返回可能的最新文件是一个很好的挑战,没有我能找到的快速现成解决方案。
完整脚本
对目标目录中所有条目的迭代测试的全面实现,从最新的最新文件向后工作,以查找第一个文件(而不是DIR)以比较时间与以下内容相似。注意:该代码已经进行了测试,但仍可能需要修复的角案例:
#!/bin/bash
path="${1:-.}" ## set path (default .)
[ "${path:(-1):1}" = '/' ] && path="${path%/}" ## strip trailing '/'
[ -d "$path" ] || { ## validate path
echo "error: invalid path provided. '$path' not found."
exit 1;
}
declare -i n=5 ## initial entries to read into array if fn is directory
declare -i oldn=1 ## save index for increased loop efficiency
## get number of files in target path
nfiles=$(wc -l < <( find "$path" -maxdepth 1 -type f ) )
(( $nfiles < 1 )) && { ## test files present in path or exit
echo "error: no files found in target directory"
exit 1
}
oldifs="$IFS" ## save old IFS, set to break on newline
IFS=$'n'
fn="${path}/$(ls -rt "$path" | tail -n1)" ## find most recent file
while [ -d "$fn" ]; do ## while fn is a directory
fnarray=( $(ls -rt "$path" | tail -n$n) ) ## read newest n entries into array
for ((i=$((${#fnarray[@]} - oldn)); i >= 0; i--)); do ## make sure newest is file
[ -f "${path}/${fnarray[i]}" ] && fn="${path}/${fnarray[i]}" && break
done
(( n == nfiles )) && break ## if all entries tried, bail
oldn=$n ## update oldn to skip next try
[ -f "$fn" ] && break || n=$(( n * 2 )) ## if file, done, else n=n*2
(( n > nfiles )) && n=nfiles ## if n > nfiles, n=nfiles
done
[ -d "$fn" ] && {
echo "error: something bad happened, no files found in target directory"
exit 1
}
IFS="$oldifs"
for i in "${path}"/*; do ## for each file in path
[ -f "$i" ] || continue ## if not a file skip
td=$(( $(stat -c %Y "$fn") - $(stat -c %Y "$i") )) ## time difference in sec
(( td < 0 )) && td=$(( td * -1 )) ## takes abs value
(( td < 10 )) && echo "$i" ## td less than X seconds, output filename
done
exit 0
以某种方式看起来像是过度的...
似乎您不仅需要最新的文件,而且还要准确地报告每个新文件。以下脚本执行此操作,通过保留跟踪上次报告的$reftime
文件:
cd "$1"
reftime=/tmp/newest-file-name
next_file=
prev_file=$(cat "$reftime" 2> /dev/null)
while true; do
read -r filename
if [[ "$prev_file" ]]; then
[[ "$filename" = "$prev_file" ]] && break # we've gotten to reported files
else
[[ -z "$filename" ]] && break # we've read past the last file
fi
next_file="$filename"
done < <(ls -t)
if [[ "$next_file" ]]; then
# Update file $reftime with time and name of the file we're about to offer
echo "$next_file" > "$reftime"
touch -r "$next_file" "$reftime"
echo "$next_file"
fi