如何知道循环中的文件是否是最后一个?

时间:2012-09-06 10:40:39

标签: bash loops

实施例

for FILE in $DIR/* 
do
  if(<is last File>)
    doSomethingSpecial($FILE)
  else
    doSomethingRegular($FILE)
  fi
done

要求<is last file>检查当前文件是否是数组中的最后一个文件?

是否有一个简单的内置检查,而不是自己检查数组的长度?

8 个答案:

答案 0 :(得分:14)

要求检查当前文件是否是数组中的最后一个文件?

首先,您没有使用数组。如果你那么这很容易:

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 

答案 1 :(得分:8)

我知道无法告诉您正在处理for循环中列表的最后一个元素。但是你可以使用一个数组,遍历除最后一个元素之外的所有元素,然后处理循环外的最后一个元素:

files=($DIR/*)
for file in "${files[@]::${#files[@]}-1}" ; do
    doSomethingRegular "$file"
done
doSomethingSpecial "${files[@]: -1:1}"

扩展${files[@]:offset:length}会对offset元素的所有元素进行求值,从length开始(如果为空,则为空)。 ${#files[@]}-1是数组中元素的数量减去1。

${files[@]: -1:1}计算到最后一个元素 - 结尾为-1,长度为1.由于:-的处理方式与: -不同,所以空格是必需的。

答案 2 :(得分:4)

试试这个

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

可生产

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

答案 3 :(得分:3)

您可以使用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

答案 4 :(得分:2)

什么使文件成为最后一个?它有什么特别之处吗?按名称排序时,它是名称最大的文件吗?

也许你可以向后取文件名。然后,它是您想要处理特殊而不是最后一个的第一个文件。弄清楚第一个是比做最后一个更容易的任务:

for file in $(ls -r1 $dir)
do
    if [ ! $processedLast ] 
    then
        doSomethingSpecial($file)
        processedLast=1
    else
        doSomethingRegular($file)
    fi
done

不需要数组。实际上,我喜欢chepner关于使用位置参数的答案。

答案 5 :(得分:1)

你可以滥用位置参数,因为它们的行为类似于数组, 但操作起来要容易一些。你应该保存旧的位置 参数,或在子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 "$1"
        shift
    done    
    doSomethingSpecial "$1"
)

# 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 "$1"
    shift
done    
doSomethingSpecial "$1"
set -- "${oldPP[@]}"

答案 6 :(得分:1)

基于@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

这会产生输出:

a
b
c
d
e
c is the last

这可确保只有数组中的 last 项触发备用操作,并且如果数组中的任何其他项重复上一个值,则替代操作 not 呼吁更早的重复。

如果是特定目录中文件的路径数组,例如

array=( $DIR/* )

...它可能不那么令人担忧,因为同一目录中的单个文件名几乎肯定是唯一的(除非你有真正的奇数文件系统!)

答案 7 :(得分:0)

这是一个古老的问题 - 但是根据@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