我正在用 bash 编写一个简单的递归 ls 程序(我对此非常没有经验,所以随意残酷)。
该程序应该在单独的行上打印出每个文件(可能是目录),并且每次进入一个新目录时,输出都会移动 4 个空格,以提供树状输出。
目前,它不会正确打印带空格的文件,并且不会在目录后放置正斜杠。(下面有更多详细信息。)
代码
recls () {
# store current working directory
# issues: seems bad to have cwd defined up here and used down below in getAbsolutePath -- too much coupling
cwd=$PWD
# get absolute path of arg
argdir=`getAbsolutePath "$@"`
# check if it exists
if [ ! -e $argdir ]; then
echo "$argdir does not exist"
return 1
fi
echo "$argdir exists"
# check if it's a directory
if [ ! -d $argdir ]; then
echo "$argdir is not a directory"
return 2
fi
echo "$argdir is a directory"
tab=""
recls_internal $argdir
return 0
}
recls_internal () {
for file in $@; do
echo -n "$tab${file##/*/}"
if [ -d $file ]; then
# print forward slash to show it's a directory
echo "/"
savedtab=$tab
tab="$tab "
myls_internal $file/*
tab=$savedtab
else
# if not a directory, print a new line
echo ""
fi
done
}
getAbsolutePath () {
if [ -z ${1##/*} ]; then
echo "$1"
else
echo "$cwd/$1"
fi
}
输出
该脚本包含在一个名为bash-practice
. 当我这样做时recls .
,我得到以下输出:
./
myls.sh
myls.sh~
recdir.sh
recls.sh
recls.sh~
sample
document.txt
sample-folder
sample-stuff
test-12.txt
test-1.txt
test-2.txt
sort-test.txt
sort-text-copy.txt
test-5-19-14-1
问题
如您所见,缩进工作正常,但有两个问题:
1)文件sample document.txt
分布在两行,因为它有一个空格。
2)每个目录前面都应该有一个正斜杠,但由于某种原因,它只适用于第一个。
尝试的解决方案
为了修复 (1),我尝试保存内部文件分隔符并将其替换为换行符,如下所示:
...
tab=""
savedIFS=$IFS
IFS="\n"
recls_internal $argdir
IFS=$savedIFS
return 0
但这根本不起作用。它甚至没有显示超过第一个文件夹。显然我对事物的理解是不正确的。
至于(2),我看不出它不应该按预期工作的任何理由。
结论
bash 对我来说很难,因为它似乎比大多数其他编程语言(作为一种 shell 脚本语言)有更多不寻常的语法,所以我希望能对我的错误有任何见解,以及解决方案。
更新#1
我去了mklement0建议的网站http://www.shellcheck.com,它的提示基本上都是双引号。当我双引号"$@"
时,程序正确地打印了文件sample document.txt
,但紧接着,它给了我一个“ binary operator expected
”错误。这是它现在的样子的打印:
更新 #2 [问题解决了吗?]
好的,事实证明我有一个错字,导致它默认为myls_internal
递归时调用的我的函数的早期版本。这个早期版本没有用正斜杠标记目录。“更新”部分中的错误消息也已修复。我换了行
myls_internal "$file/*"
到
recls_internal $file/*
现在它似乎工作正常。如果有人正在写答案,我仍然感谢您的见解,因为我并不真正了解引用“$@”如何解决间距问题的机制。
固定代码:
recls () {
# store current working directory
# issues: seems bad to have cwd defined up here and used down below in getAbsolutePath -- too much coupling
cwd=$PWD
# get absolute path of arg
argdir=$(getAbsolutePath "$@")
# check if it exists
if [ ! -e $argdir ]; then
echo "$argdir does not exist"
return 1
fi
echo "$argdir exists"
# check if it's a directory
if [ ! -d $argdir ]; then
echo "$argdir is not a directory"
return 2
fi
echo "$argdir is a directory"
tab=""
recls_internal $argdir
return 0
}
recls_internal () {
for file in "$@"; do
echo -n "$tab${file##/*/}"
if [ -d "$file" ]; then
# print forward slash to show it's a directory
echo "/"
savedtab=$tab
tab="$tab "
recls_internal $file/*
tab=$savedtab
else
# if not a directory, print a new line
echo ""
fi
done
}
getAbsolutePath () {
if [ -z ${1##/*} ]; then
echo "$1"
else
echo "$cwd/$1"
fi
}
固定输出:
更新#3
线
recls_internal $file/*
应该改为
recls_internal "$file"/*
它正确处理带有空格的目录。否则,一个文件夹,如cs 350
包含Homework1.pdf
和Homework2.pdf
将展开为
cs 350/Homework1.pdf 350/Homework2.pdf
什么时候应该
cs 350/Homework1.pdf cs 350/Homework2.pdf
我认为?我并没有真正了解正在发生的事情的更详细的信息,但这似乎解决了它。