如何通过 shell 脚本创建显示所有目录的命令?
How to create a command that shows all directories, through a shell script?
我想创建一个命令来显示作为参数给定的目录中的所有目录。例如,如果我们的文件层次结构是这样的:
dir1:
dir2
dir3
file1
dir4:
file2
dir5
那么rep dir1
的结果应该是:
dir2
dir3
dir4
而 rep dir1/dir4
应该显示:
dir5
目前我有一个 shell 脚本 rep.sh
执行以下操作:
function rep(){
all=`ls `
for each in $all
do
if [ -d $each ]
then
echo $each
fi
done
}
通过 bash rep.sh
执行此脚本不会执行任何操作,我认为这是正确的,但是当我执行 rep dir1
或 rep dir1/dir4
时它不会显示任何内容。我认为我的错误在于我没有正确使用函数环境,或者我没有正确传递参数。
...
find "" -mindepth 1 -maxdepth 1 -type d -exec basename {} \;
...
选项-mindepth 1
和-maxdepth 1
阻止列出基目录或下降到子目录。 -type d
应用过滤器以便仅列出目录,并且 -exec basename {} \;
对找到的项目执行 basename
。 basename
剥离路径,以便仅打印目录名称本身。
纯Bash:
rep() {
for dir in ""/*/; do
dir=${dir%/}
printf '%s\n' "${dir##*/}"
done
}
glob ""/*/
获取所有目录;两个参数扩展然后删除尾部斜杠和目录路径。
这会忽略隐藏目录;如果您也想要这些,则必须打开 dotglob
shell 选项。要保留 shell 选项的设置,您可以像这样包装函数:
rep() {
local dg
# Get current dotglob setting
dg=$(shopt -p dotglob)
# Enable dotglob
shopt -s dotglob
for dir in ""/*/; do
dir=${dir%/}
printf '%s\n' "${dir##*/}"
done
# Set dotglob back to what it was
$dg
}
至于为什么你的脚本不起作用:在你分配给它之后看看 all
中包含的内容。
$ all=$(ls "")
$ declare -p all
declare -- all="dir2
dir3
dir4
file1"
(请注意,我还用 $()
和双引号 </code> 替换了过时的反引号。)</p>
<p><code>ls
的输出不包含目录的路径,这就是为什么你的 -d
测试 returns 一切都是假的。
您使用 ls
的方式很容易出错:分词和参数扩展会使这样的脚本对于任何带有空白或 shell 元字符的文件名都失败(请参阅 Why you shouldn't parse the output of ls(1)
).请改用 glob。
三个错误:
1)
的用法
all=`ls `
而不是
all=""/*
@Benjamin W. 指出。
2) 我忘记将 rep
放在 rep.sh
文件的末尾。该文件因此看起来像:
function rep(){
all=""/*
for each in $all
do
if [ -d $each ]
then
echo $each
fi
done
}
rep
3) 在命令行中,我需要输入alias rep="bash rep.sh"
才能在命令行中自由使用命令rep
。
我想创建一个命令来显示作为参数给定的目录中的所有目录。例如,如果我们的文件层次结构是这样的:
dir1:
dir2
dir3
file1
dir4:
file2
dir5
那么rep dir1
的结果应该是:
dir2
dir3
dir4
而 rep dir1/dir4
应该显示:
dir5
目前我有一个 shell 脚本 rep.sh
执行以下操作:
function rep(){
all=`ls `
for each in $all
do
if [ -d $each ]
then
echo $each
fi
done
}
通过 bash rep.sh
执行此脚本不会执行任何操作,我认为这是正确的,但是当我执行 rep dir1
或 rep dir1/dir4
时它不会显示任何内容。我认为我的错误在于我没有正确使用函数环境,或者我没有正确传递参数。
...
find "" -mindepth 1 -maxdepth 1 -type d -exec basename {} \;
...
选项-mindepth 1
和-maxdepth 1
阻止列出基目录或下降到子目录。 -type d
应用过滤器以便仅列出目录,并且 -exec basename {} \;
对找到的项目执行 basename
。 basename
剥离路径,以便仅打印目录名称本身。
纯Bash:
rep() {
for dir in ""/*/; do
dir=${dir%/}
printf '%s\n' "${dir##*/}"
done
}
glob ""/*/
获取所有目录;两个参数扩展然后删除尾部斜杠和目录路径。
这会忽略隐藏目录;如果您也想要这些,则必须打开 dotglob
shell 选项。要保留 shell 选项的设置,您可以像这样包装函数:
rep() {
local dg
# Get current dotglob setting
dg=$(shopt -p dotglob)
# Enable dotglob
shopt -s dotglob
for dir in ""/*/; do
dir=${dir%/}
printf '%s\n' "${dir##*/}"
done
# Set dotglob back to what it was
$dg
}
至于为什么你的脚本不起作用:在你分配给它之后看看 all
中包含的内容。
$ all=$(ls "")
$ declare -p all
declare -- all="dir2
dir3
dir4
file1"
(请注意,我还用 $()
和双引号 </code> 替换了过时的反引号。)</p>
<p><code>ls
的输出不包含目录的路径,这就是为什么你的 -d
测试 returns 一切都是假的。
您使用 ls
的方式很容易出错:分词和参数扩展会使这样的脚本对于任何带有空白或 shell 元字符的文件名都失败(请参阅 Why you shouldn't parse the output of ls(1)
).请改用 glob。
三个错误:
1)
的用法all=`ls `
而不是
all=""/*
@Benjamin W. 指出。
2) 我忘记将 rep
放在 rep.sh
文件的末尾。该文件因此看起来像:
function rep(){
all=""/*
for each in $all
do
if [ -d $each ]
then
echo $each
fi
done
}
rep
3) 在命令行中,我需要输入alias rep="bash rep.sh"
才能在命令行中自由使用命令rep
。