Bash捕获带有排除的find输出到While循环中

时间:2014-05-20 04:35:51

标签: bash while-loop find

我创建了一个脚本,以递归方式查找文件夹的内容,排除某些路径,然后要求对结果的每一行采取操作。

find命令本身工作正常,并按预期排除路径。看起来像这样:

$SOURCE="FOLDER/"
$EXCLUDESTRING="! -path \"FOLDER/*/.svn/*\" ! -path \"FOLDER/uploads/*\" ! -path \"FOLDER/ai-cache/*\""

find "$SOURCE"* $EXCLUDESTRING # uploads and ai-cache folders are not included in the results

但是当我将结果传递给While循环时,它不会考虑排除。

find "$SOURCE"* $EXCLUDESTRING -print0 | while read -d $'\0' file_1
do
    echo $file_1 # uploads and ai-cache folders are included in the results
    if statement ...
    more commands ...
done

我想提一下,目标是找到所需的文件和文件夹,并在不使用数组的情况下即时处理它们。


更新


对于那些对我的脚本感兴趣的人(逐步单向同步)或者可以测试(非常感谢)这是一个更详细的副本:

#!/bin/bash
excludepath=( "*/.svn/*" "uploads/*" "design/*" "ai-cache/*" )
bold=`tput bold`
normal=`tput sgr0`
validsource="false"
while [ "$validsource" == "false" ]
do
    echo ""
    echo "Specify project to compare :"
    echo -n "/home/myaccount/public_html/projects/"
    read -e project
    project=`echo "$project" | sed -e "s/\/*$//" `
    projectpath="/home/myaccount/public_html/projects/$project"
    source="$(readlink -f $projectpath)/"
    if [ -d "$source" ];then
        validsource="true"
    else
        echo "The working copy cannot be found ($projectpath)."
    fi
done
echo "Compare project with folder :"
read -e target
excludestring=""
for i in "${excludepath[@]}"
do
    excludestring="$excludestring ! -path \"$source$i\""
done
echo ""
echo "______________________________________________"
echo ""
echo "COMPARISON IN PROGRESS ..."
echo "______________________________________________"
echo ""
echo "List of paths excluded from the comparison: ${excludepath[@]}"
echo "Executed command : find \"$source\"* $excludestring"
echo ""
liveexclude=()
find "$source"* $excludestring -print0 | while read -d $'\0' file_1
do
    file=$( echo "$file_1" | sed "s,$source,,g" ) # Strip base path
    file_2=$( echo "$file_1" | sed "s,$source,$target,g" ) # Getting file path in $target
    dir=$( dirname "$file_2" | sed "s,$target,,g" )
    dir_1=$( dirname "$file_1" )
    dir_2=$( dirname "$file_2" )
    #Check for live excluded folders
    process="true"
    for i in "${liveexclude[@]}"
    do
        if [[ $file_1 == "$i"* ]]
        then
            process="false"
            break
        fi
    done

    if [ "$process" == "true" ];then
        if [ -d "$file_1" ];then
            if [ ! -d "$file_2" ] # Checking if sub-dir exists in $target
            then
                while [ "$confirm" != "y" ] && [ "$confirm" != "n" ]
                do
                    echo ""
                    echo "${bold}Folder${normal} \"$file\" doesn't exist."
                    echo -n "Would you like to ${bold}create it and its entire contents${normal} ? (y/n) "
                    read -e confirm </dev/tty
                done
                if [ "$confirm" == "y" ];then
                    mkdir -p $file_2                                                # Creating if sub-dir missing
                    cp -r "$file_1/"* "$file_2"
                fi
                confirm=""

                liveexclude+=("$file_2")
            fi
        else
            if [ -f "$file_1" ];then
                if [ -f "$file_2" ]                                                 # Checking if file exists in $target
                then
                    cksum_file_1=$( cksum "$file_1" | cut -f 1 -d " " )             # Get cksum of file in $source
                    cksum_file_2=$( cksum "$file_2" | cut -f 1 -d " " )             # Get cksum of file in $target

                    if [ $cksum_file_1 -ne $cksum_file_2 ]                          # Check if cksum matches
                    then
                        while [ "$confirm" != "y" ] && [ "$confirm" != "n" ]
                        do
                            if [ "$file_1" -nt "$file_2" ]
                            then
                                echo ""
                                echo "${bold}File${normal} \"$file\" is not updated."
                                echo -n "Would you like to ${bold}replace${normal} it ? (y/n) "
                            else
                                echo ""
                                echo "${bold}File${normal} \"$file\" was modified."
                                echo "${bold}CAUTION${normal}: The file \"$file_2\" is newer than the file \"$file_1\""
                                echo -n "Would you still ${bold}overwrite${normal} it ? (y/n) "
                            fi
                            read -e confirm </dev/tty
                        done
                        if [ "$confirm" == "y" ];then
                            cp "$file_1" "$file_2"                                      # Copy if cksum mismatch
                        fi
                        confirm=""
                    fi
                else
                    while [ "$confirm" != "y" ] && [ "$confirm" != "n" ]
                    do
                        echo ""
                        echo "${bold}File${normal} \"$file\" doesn't exist."
                        echo -n "Would you like to ${bold}copy${normal} it ? (y/n) "
                        read -e confirm </dev/tty
                    done
                    if [ "$confirm" == "y" ];then
                        cp "$file_1" "$file_2"                                          # Copy if file does not exist.
                    fi
                    confirm=""
                fi
            fi
        fi
    fi
done

PS。如果需要进行详细检查,我们使用此脚本在现有项目上应用新更改。

2 个答案:

答案 0 :(得分:2)

不要将命令放在字符串中,而是放在数组中。并且不要在作业的左侧使用一美元(我们不在Perl / PHP中)。哦,避免使用大写变量名。它看起来很难看;你好像在喊这个变量的名字;但更严重的是,它可能会与保留名称冲突(例如PATHLINESGROUPSUSERS等等;如果您坚持使用小写变量名称,那么您就安全了(而且它更漂亮!)。

source=FOLDER/
excludeary=( \! -path "FOLDER/*/.svn/*" \! -path "FOLDER/uploads/*" \! -path "FOLDER/ai-cache/*" )

find "$source" "${excludeary[@]}" -print0 | while IFS= read -r -d '' file_1
do
    echo "$file_1" # uploads and ai-cache folders are included in the results
    if statement ...
    more commands ...
done

编辑。以下是一个小例子:

$ mkdir Test
$ cd Test
$ mkdir -p {excl,incl}/{1,2}
$ touch {excl,incl}/{1,2}/{a,b}
$ tree
.
|-- excl
|   |-- 1
|   |   |-- a
|   |   `-- b
|   `-- 2
|       |-- a
|       `-- b
`-- incl
    |-- 1
    |   |-- a
    |   `-- b
    `-- 2
        |-- a
        `-- b

6 directories, 8 files
$ source=~/Test
$ excludeary=( \! -path "$source/excl/*" )
$ find "$source" "${excludeary[@]}"
/home/gniourf/Test
/home/gniourf/Test/excl
/home/gniourf/Test/incl
/home/gniourf/Test/incl/1
/home/gniourf/Test/incl/1/a
/home/gniourf/Test/incl/1/b
/home/gniourf/Test/incl/2
/home/gniourf/Test/incl/2/a
/home/gniourf/Test/incl/2/b

! -path的工作原理。请注意,您仍然拥有/home/gniourf/Test/excl文件夹(但不包含其子文件夹)。也许你想要-prune代替:

$ pruneary=( \! \( -type d -name excl -prune \) )
$ find "$source" "${pruneary[@]}"
/home/gniourf/Test
/home/gniourf/Test/incl
/home/gniourf/Test/incl/1
/home/gniourf/Test/incl/1/a
/home/gniourf/Test/incl/1/b
/home/gniourf/Test/incl/2
/home/gniourf/Test/incl/2/a
/home/gniourf/Test/incl/2/b

或者将所有1目录与excl目录一起排除:

$ excludeary=( \! \( -type d \( -name excl -o -path '*/1' \) -prune \) )
$ find "$source" "${excludeary[@]}"
/home/gniourf/Test
/home/gniourf/Test/incl
/home/gniourf/Test/incl/2
/home/gniourf/Test/incl/2/a
/home/gniourf/Test/incl/2/b

答案 1 :(得分:0)

当我删除所有双引号并将所有内容放在单引号中时,所有必要的排除对我都有用:

EXCLUDESTRING='! -path FOLDER/*/.svn/* ! -path \"FOLDER/uploads/* ! -path FOLDER/ai-cache/*'