shell 我的bash代码不满足循环条件,但仍会循环(+不起作用)

2exbekwf  于 2022-12-13  发布在  Shell
关注(0)|答案(2)|浏览(123)

因此,我创建了一个bash脚本,它递归地搜索包含您引入的单词的文件,然后创建一个与引入的变量同名的文件夹(如果该文件夹不存在),最后它将所有满足该单词的文件复制到新文件夹中。
例如,如果我有一个名为“files_1906”的文件夹,其中有一个名为“hello_1906.pdf”的文件,然后有另一个名为“hello”的文件夹(不在第一个文件夹中),其中有一个名为“1906 hello”的文件,如果我引入:.sh program_name.sh“1906”,它应该创建一个名为1906的文件夹,并在其中复制两个文件。
但现在我只设法创建文件夹,它不复制文件。
下面是完整的代码:

#!/bin/bash
currentDir=$(pwd)
for var in "$@"
do
    countCurrentWord=$(find . -type f -name "$var" | grep "$var" | wc -l)
    echo -e "$countCurrentWord"
    echo -e "Number of files matching the keyword $var: $countCurrentWord"
    if [[ $countCurrentWord -gt 0 ]]
    then
        if [[ -d $currentDir/$var ]]
        then
            echo -e "the folder $var already exists, copying the files...\n"
        else
            mkdir "$currentDir"/"$var"
            echo -e "the folder $var does not exist, creating the folder and copying the files...\n"
        fi
        IFS=$'\n'
        array=$(find . -type f -name "$var")
        declare -p array > /dev/null 2>&1
        declare -a array > /dev/null 2>&1
        length=${#array[@]}
        for ((i=0; i < length; i++))
        do
            cp "${array[i]}" "$currentDir"/"$var"/ > /dev/null 2>&1
            echo -e "hello world"
        done
    else
        echo -e "no files found, no move will be made.\n"
    fi
done

控制台将返回以下内容:
首先,它表示$countCurrentWord = 0,这没有任何意义,因为存在包含“1906”的文件
但这就是问题所在:
程序忽略大于0的值,开始循环,创建一个名为1906的文件夹,但之后,它不复制文件,一旦创建,它就保持为空。我还从第二个循环中得到了hello world。
那么,我们如何解决这个问题,使它做它的工作和复制文件?
我已经尝试了文件名只有“1906”(也不工作),但脚本应该能够阅读文件的全名,并辨别是否包含关键字介绍。我不知道我有一个错字或任何东西,我没有在bash脚本的经验
我希望我解释得足够好,这样你们就可以帮助我,谢谢你们的努力!

nfeuvbwi

nfeuvbwi1#

完全重写:对每个提交的单词只运行一次find,并使用reliablebash变量存储找到的文件名。

#!/bin/bash
shopt -s extglob
currentDir=$(pwd)
for var ;do
    mapfile  -d '' -t FoundFiles < <(
        find !($var) -type f -iname "*$var*" -print0
    )
    if (( ${#FoundFiles[@]} > 0 )) ;then
        if [[ -d $currentDir/$var ]] ;then
            printf 'Folder %s already exist.\n' "$var"
        else
            printf 'Create new folder '%s'.\n' "$var"
            mkdir "$currentDir/$var"
        fi
        cp -at "$currentDir/$var" "${FoundFiles[@]}"
    else
        printf 'No file found with \47%s\47.\n' "$var"
    fi
done
  • 通过使用shopt -s extglobfind !($var),避免find浏览名为$var的文件夹。
  • 在第4行for var; do中,常见情况in "$@"implicit
  • cp -ait "/path/to/target" "${array[@]}"是可靠,可以使用特殊的文件名等等。

我没有添加echo "hello world"命令,但您可以随意添加v标志到cp命令:

cp -avt "$currentDir/$var" "${FoundFiles[@]}"

...和/或覆盖前询问的i标志:

cp -viat "$currentDir/$var" "${FoundFiles[@]}"
bnl4lu3b

bnl4lu3b2#

1)您将$var字符串作为literalmkdir一起使用,作为文件名globfind一起使用,以及作为extended regexgrep一起使用。这些字符在每个上下文中可以有不同的含义。

考虑到最终目标,可以丢弃grep,因此只需确保$varglob中使用时保持literal含义。下面是使用awk进行全局转义的方法:
第一个

**注意:**任意路径的唯一有效分隔符是NUL字节。

嗯,这就是它的要点;没有理由为$@中的每个$var触发一个awk,因为您可以一次性执行所有全局转义,并在对$@进行迭代时逐个读取它们:

#!/bin/bash
  
for var in "$@"
do
    IFS='' read -r -d '' var_glob_safe

    # ...

done < <(
    LANG=C awk '
        BEGIN {
            for (i = 1; i < ARGC; i++) {
                gsub(/[\\?*[]/,"\\\\&", ARGV[i])
                printf "%s%c", ARGV[i], 0
            }
        }
    ' "$@"
)

**2)**要查找名称中包含$var_glob_safe的文件,命令应为:

find . -type f -name "*$var_glob_safe*"

但是,您希望用结果填充bash数组,因此必须告诉find使用NUL字节分隔符(使用-print0)并填充数组,如下所示:

# for bash >= 4.3
readarray -t -d '' files < <(
    find . -type f -name "*$var_glob_safe*" -print0
)

# for bash < 4.3
files=()
while IFS='' read -r -d '' f
do
    files+=( "$f" )
done <(
    find . -type f -name "*$var_glob_safe*" -print0
)

现在,您可以使用${#files[@]}访问“文件”的总数,因此您可以将逻辑建立在此基础上。

**3)**下面的代码包含了上述解释和更多内容;唯一缺少的部分是echo s:

#!/bin/bash
  
for var in "$@"
do
    [[ $var == */* ]] && exit 1 # a filename can't contain a slash

    IFS='' read -r -d '' var_glob_safe

    readarray -d '' files < <(
        find . -type f -name "*$var_glob_safe*" -print0
    )

    if (( ${#files[@]} )) 
    then 
        mkdir -p "$var" || exit 1
        cp "${files[@]}" "$var"
    fi
done < <(
    awk '
        BEGIN {
            for (i = 1; i < ARGC; i++) {
                gsub(/[\\?*[]/,"\\\\&", ARGV[i])
                printf "%s%c", ARGV[i], 0
            }
        }
    ' "$@"
)

相关问题