[英]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.