简体   繁体   English

ubuntu / linux bash:遍历目录和子目录以使用文件

[英]ubuntu/linux bash: traverse directory and subdirectories to work with files

let me start off with what I need; 让我从我需要的东西开始; the program is given a directory, it will then examine all the files in the directory (works) and do stuff to the files (waiting till it can find all the files for this part). 给程序一个目录,它将检查该目录中的所有文件(有效)并对文件进行填充(等待直到可以找到该部分的所有文件)。 then it will look for subdirectories and re-run its self for each subdirectory. 然后它将查找子目录并为每个子目录重新运行其自身。

the directory I'm testing with looks like this: 我正在测试的目录如下所示:

desktop/test_files/ (starting directory)
desktop/test_files/folder 1/
desktop/test_files/folder 1>folder 2/
desktop/test_files/folder 1>folder 2/<files, 20 or so>
desktop/test_files/folder 3/
desktop/test_files/folder 3/<more files, 20 or so>

folders and files do contain spaces in the names 文件夹和文件的名称中确实包含空格

the output is: 输出为:

$ ./x007_shorter.sh Desktop/test_files/

Desktop/test_files/"folder 1"/
Desktop/test_files/folder 1/"folder 2"/
ls: cannot access */: No such file or directory
Desktop/test_files/folder 1/folder 2/"folder 3"/
./x007_shorter.sh: line 4: cd: ./folder 3/: No such file or directory
ls: cannot access */: No such file or directory

here is the program: 这是程序:

#!/bin/bash
function findir {
    newDir=$1
    eval cd $newDir
    ARRAY=( $(ls -d */) )
    declare -a diry
    count=0
    a=0
    while [ $a -lt ${#ARRAY[@]} ]; do
        diry[$count]="${ARRAY[$a]}"
        noSpace=true
        while [ true ]; do
            if [[ ${diry[$count]} == */* ]] ; then
                if [ $noSpace = false ]; then
                diry[$count]="${diry[$count]:0:((${#diry[$count]}-1))}\"/"
                fi
                break
                noSpace=true
            fi
            let "a=$a+1"
            if [ $noSpace = false ]; then
                diry[$count]="${diry[$count]} ${ARRAY[$a]}"
            else
                diry[$count]="\"${diry[$count]} ${ARRAY[$a]}"
            fi
            noSpace=false
        done
        let "count=$count+1"
        let "a=$a+1"
    done
    for a in `seq 1 ${#diry[@]}`; do
        eval cd .$newDir
#        list "${diry[($a-1)]}"
        where=`pwd`
#        eval cd $newDir
        #findir "${diry[($a-1)]}"
        #findir "$where${diry[($a-1)]:1}"
        #Right option won,  echo "${diry[($a-1)]} Vs $where/${diry[($a-1)]}"
        echo "$where/${diry[($a-1)]}"
        findir "./${diry[($a-1)]}"
    done
}
function list {
    input_file_directory=$1
    eval cd $input_file_directory
    ARRAY=( $(find . -maxdepth 1 -type f -print) )
    declare -a files
    count=0
    a=0
    while [ $a -lt ${#ARRAY[@]} ]; do
        files[$count]="${ARRAY[$a]}"
        while [ true ]; do
            if [[ ${ARRAY[(($a+1))]} == ./* ]] ; then
                break
            fi
            if [[ "${ARRAY[(($a+1))]}" == "" ]] ; then
                break
            fi
            let "a=$a+1"
            files[$count]="${files[$count]} ${ARRAY[$a]}"
        done
        let "count=$count+1"
        let "a=$a+1"
    done
    where=`pwd`
    for a in `seq 1 ${#files[@]}`; do
        echo "$where${files[($a-1)]:1}"
        #going to work on each file, just echoing file till lists all files
    done
}

clear
dar=""
if [[ $1 = "" ]]; then
    read -p "Please enter a directory for me to scan" newdir
    dar=$newdir
    list $newdir
    findir $newdir
else
    dar=$1
    list $1
    findir $1
fi

Any reason you can't use find for this? 您无法为此使用find的任何原因? Stick the per-file operation you want in it's own script (I've called it dostufftomyfile.sh below), then do: 将所需的每个文件操作粘贴在自己的脚本中(下面将其称为dostufftomyfile.sh),然后执行以下操作:

find $dir -type f -print0 | xargs -0 dostufftomyfile.sh

Replacing $dir with the top level directory you'll be searching from... 将$ dir替换为您要从中搜索的顶级目录...

Edited to add... When you write the shell script, make sure you put $@ in double-quotes... eg, you'll want your dostufftomyfile.sh script to have this structure: 编辑为添加...在编写shell脚本时,请确保将$ @放在双引号中...例如,您将希望dostufftomyfile.sh脚本具有以下结构:

#!/bin/sh
for f in "$@"
do
    echo "Processing file: $f"
    # Do something to file $f
done

if you don't quote $@ then the spaces in filenames will be ignored (which I suspect you won't want) :-) 如果您不引用$ @,则文件名中的空格将被忽略(我怀疑您不希望这样做):-)

Chris J's answer is the preferred way to do things if you can put the per-file stuff in a separate command(/script). 如果可以将每个文件的内容放在单独的命令(/ script)中,则Chris J的答案是首选的处理方式。 If you want everything in a single script, my favorite incantation is something like this: 如果您希望所有内容都在一个脚本中,那么我最喜欢的咒语是这样的:

while IFS="" read -r -d $'\000' file <&3; do
    dostuffwith "$file"
done 3< <(find -x  "$dir" -mindepth 1 -type f -print0)

See BashFAQ #20 and #89 for explanations and some other options. 有关说明和其他一些选项,请参见BashFAQ#20#89 Note that this only works in bash (ie the script must start with #!/bin/bash). 请注意,这仅适用于bash(即脚本必须以#!/ bin / bash开头)。 Also, it processes the contents of a given directory in alphabetic order, rather than files-before-subdirectories. 同样,它按字母顺序处理给定目录的内容,而不是子目录之前的文件。

If you really want to step through the files "by hand" (ie to get more control over the traversal order), here's how I'd do it: 如果您真的想“手动”浏览文件(即对遍历顺序进行更多控制),请按以下步骤操作:

#!/bin/bash

process_dir() {
    local -a subdirs=()
    echo "Scanning directory: $1"

    # Scan the directory, processing files and collecting subdirs
    for file in "$1"/*; do
        if [[ -f "$file" ]]; then
            echo "Processing file: $file"
            # actually deal with the file here...
        elif [[ -d "$file" ]]; then
            subdirs+=("$file")
            # If you don't care about processing all files before subfolders, just do:
            # process_dir "$file"
        fi
    done

    # Now go through the subdirs
    for d in "${subdirs[@]}"; do
        process_dir "$d"
    done
}

clear
if [[ -z "$1" ]]; then
    read -p "Please enter a directory for me to scan " dir
else
    dir="$1"
fi
process_dir "$dir"

You have the error "No such file .... due to this 您有错误"No such file ....由于这个

ARRAY=( $(ls -d */) )

When its expanded, directories with whitespaces will get stored in array as individual elements. 展开后,带有空格的目录将作为单个元素存储在数组中。 eg Desktop/test_files/folder 1/folder 2/"folder 3"/ . 例如Desktop/test_files/folder 1/folder 2/"folder 3"/

In the array, element 0 will be Desktop/test_files/folder , element 1 will be 1/folder and so on. 在数组中,元素0将为Desktop/test_files/folder ,元素1将为1/folder ,依此类推。 That's why your script can't find the directory. 这就是为什么脚本无法找到目录的原因。

You can set the IFS to $'\\n' before assigning to the array 您可以在分配给数组之前将IFS设置为$'\\ n'

OLDIFS=$IFS
IFS=$'\n'
ARRAY=($(ls -d */))
IFS="$OLDIFS"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 重命名Linux目录和子目录中的所有文件 - Rename All Files in directory and subdirectories Linux 删除linux中目录的所有子目录中的特定文件 - Delete particular files in all subdirectories of a directory in linux bash - 遍历子目录、cat 文件并用目录名重命名 - bash - loop through subdirectories, cat files and rename with directory name Bash / Shell-将子目录中的所有文件移动到目标目录中? - Bash/Shell-Move all files from subdirectories into target directory? 列出具有特定模式文件名的linux目录和子目录中的所有文件 - list all files in directory and subdirectories in linux with specific pattern filename 创建目录和子目录的Bash文件 - Bash file that creates a directory and subdirectories Linux Bash脚本取消隐藏目录中的文件 - Linux Bash Script unhiding files in the directory Linux,使用bash重命名文件“无此文件或目录”错误 - Linux, rename files with bash 'no such file or directory' error bash脚本linux - 使用目录作为用户输入参数,并将所有子目录复制到/ tmp / folder,其名称与输入目录相同 - bash script linux - use directory as user input parameter and copy all the subdirectories to /tmp/ folder with the same name as the input directory 如何将目录中的大量zip文件移动到bash中指定数量的多个子目录中? - How do I move a large number of zip files in a directory to a specified number of multiple subdirectories in bash?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM