bash 如何知道循环中的文件是否是最后一个?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12298261/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to know if file in a loop is the last one?
提问by John Threepwood
Example
例子
for FILE in $DIR/*
do
if(<is last File>)
doSomethingSpecial($FILE)
else
doSomethingRegular($FILE)
fi
done
What to call for <is last file>to check if the current file is the last one in the array ?
调用什么来<is last file>检查当前文件是否是数组中的最后一个?
Is there an easy built-in check without checking the array's length by myself ?
是否有一个简单的内置检查而无需自己检查数组的长度?
回答by cdarke
What to call for to check if the current file is the last one in the array ?
调用什么来检查当前文件是否是数组中的最后一个?
For a start, you are not using an array. If you were then it would be easy:
首先,您没有使用数组。如果你是,那就很容易了:
declare -a files
files=($DIR/*)
pos=$(( ${#files[*]} - 1 ))
last=${files[$pos]}
for FILE in "${files[@]}"
do
if [[ $FILE == $last ]]
then
echo "$FILE is the last"
break
else
echo "$FILE"
fi
done
回答by camh
I know of no way to tell that you are processing the last element of a list in a for loop. However you could use an array, iterate over all but the last element, and then process the last element outside the loop:
我不知道如何判断您正在 for 循环中处理列表的最后一个元素。但是,您可以使用数组,迭代除最后一个元素之外的所有元素,然后处理循环外的最后一个元素:
files=($DIR/*)
for file in "${files[@]::${#files[@]}-1}" ; do
doSomethingRegular "$file"
done
doSomethingSpecial "${files[@]: -1:1}"
The expansion ${files[@]:offset:length}evaluates to all the elements starting at offset(or the beginning if empty) for lengthelements. ${#files[@]}-1is the number of elements in the array minus 1.
扩展${files[@]:offset:length}计算所有元素的开始offset(如果为空,则为开始)length。${#files[@]}-1是数组中的元素数减 1。
${files[@]: -1:1}evaluates to the last element - -1 from the end, length 1. The space is necessary as :-is treated differently to : -.
${files[@]: -1:1}计算到最后一个元素 - 从末尾开始 -1,长度为 1。空格是必要的,因为:-与 的处理方式不同: -。
回答by Greg Reynolds
Try this
尝试这个
LAST_FILE=""
for f in *
do
if [ ! -z $LAST_FILE ]
then
echo "Process file normally $LAST_FILE"
fi
LAST_FILE=$f
done
if [ ! -z $LAST_FILE ]
then
echo "Process file as last file $LAST_FILE"
fi
Produces
生产
bash[1051]: ls
1 2 3 4
bash[1052]: sh ../last_file.sh
Process file normally 1
Process file normally 2
Process file normally 3
Process file as last file 4
回答by Ubuntuser
You can use find to find the total number of files. Then when you are in the loop count to the total number and carry out your task when the total equals the count i.e, the last file.
您可以使用 find 来查找文件总数。然后当您在循环中计数到总数并在总数等于计数时执行您的任务,即最后一个文件。
f=0
tot_files=`find . -iname '*.txt' | wc -l`
for FILE in $DIR/*
do
f=($f+1)
if [[ $f == $tot_files ]];then
carryout your task
fi
done
回答by jimbobmcgee
Building on the current highest-voted answer from @cdarke (https://stackoverflow.com/a/12298757/415523), if looking at a general array of values (rather than specifically files on disk), the loop code would be as follows:
基于@cdarke(https://stackoverflow.com/a/12298757/415523)的当前最高投票答案,如果查看一般值数组(而不是磁盘上的特定文件),循环代码将如下如下:
declare -a array
declare -i length current
array=( a b c d e c )
length=${#array[@]}
current=0
for VALUE in "${array[@]}"; do
current=$((current + 1))
if [[ "$current" -eq "$length" ]]; then
echo "$VALUE is the last"
else
echo "$VALUE"
fi
done
This yields the output:
这产生了输出:
a
b
c
d
e
c is the last
This ensures that only the lastitem in the array triggers the alternative action and that, if any other item in the array duplicates the last value, the alternative action is notcalled for the earlier duplicates.
这确保只有数组中的最后一项触发替代操作,并且如果数组中的任何其他项复制了最后一个值,则不会为较早的重复项调用替代操作。
In the case of an array of paths to filesin a specific directory, e.g.
如果是特定目录中文件的路径数组,例如
array=( $DIR/* )
...it is probably less of a concern, since individual filenames within the same directory are almost-certainly unique (unless you have a reallyodd filesystem!)
...这可能不太重要,因为同一目录中的各个文件名几乎肯定是唯一的(除非您有一个非常奇怪的文件系统!)
回答by David W.
What makes a file the last one? Is there something special about it? Is it the file with the greatest name when sorted by name?
是什么让文件成为最后一个?它有什么特别之处吗?按名称排序时,它是名称最大的文件吗?
Maybe you can take the file names backwards. Then, it's the first file you want to treat special and not the last. figuring out the first is a much easier task than doing the last:
也许你可以把文件名倒过来。然后,它是您要特殊处理的第一个文件,而不是最后一个。找出第一个比做最后一个容易得多:
for file in $(ls -r1 $dir)
do
if [ ! $processedLast ]
then
doSomethingSpecial($file)
processedLast=1
else
doSomethingRegular($file)
fi
done
No arrays needed. Actually, I like chepner's answer about using positional parameters.
不需要数组。实际上,我喜欢chepner关于使用位置参数的回答。
回答by yatsek
It's old question - but building on answer from @GregReynolds please use this one-liner if commands differ only by parameters on last pass. Ugly, ugly code for one-liner lovers
这是一个老问题 - 但如果命令仅因最后一次传递的参数不同,则基于@GregReynolds 的回答,请使用此单行。单线爱好者的丑陋,丑陋的代码
( ff="" ; for f in * "" ; do [ -n "$ff" ] && echo $(${f:+false} && echo $ff alternate params here || echo normal params $ff ) ; ff=$f ; done )normal params 1
normal params 2
normal params 3
4 alternate params here
( ff="" ; for f in * "" ; do [ -n "$ff" ] && echo $(${f:+false} && echo $ff alternate params here || echo normal params $ff ) ; ff=$f ; done )normal params 1
normal params 2
normal params 3
4 alternate params here
回答by chepner
You can abuse the positional parameters, since they act similarly to an array, but are a little easier to manipulate. You should either save the old positional parameters, or execute in a subshell.
您可以滥用位置参数,因为它们的作用类似于数组,但更易于操作。您应该保存旧的位置参数,或者在子 shell 中执行。
# Method 1: use a subshell. Slightly cleaner, but you can't always
# do this (for example, you may need to affect variables in the current
# shell
files=( $DIR/* )
(
set -- "${files[@]}"
until (( $# == 1 )); do
doSomethingRegular ""
shift
done
doSomethingSpecial ""
)
# Method 2: save the positional parameters. A bit uglier, but
# executes everything in the same shell.
files=( $DIR/* )
oldPP=( "$@" )
set -- "${files[@]}"
until (( $# == 1 )); do
doSomethingRegular ""
shift
done
doSomethingSpecial ""
set -- "${oldPP[@]}"

