请找到下面的代码来显示当前文件夹中的目录。
- 什么是
${arg##/*/}
在shell脚本中的含义。 (arg#*
和arg##/*/
给出相同的输出。) {} \;
在for循环语句中的含义是什么。
for arg in `find . -type d -exec ls -d {} \;`
do
echo "Output 1" ${arg##/*/}
echo "Output 2" ${arg#*}
done
请找到下面的代码来显示当前文件夹中的目录。
${arg##/*/}
在shell脚本中的含义。 (arg#*
和arg##/*/
给出相同的输出。){} \;
在for循环语句中的含义是什么。for arg in `find . -type d -exec ls -d {} \;`
do
echo "Output 1" ${arg##/*/}
echo "Output 2" ${arg#*}
done
添加到@常总的有用的答案:
${arg#*}
是根本毫无意义扩张,其结果总是相同$arg
本身,因为它剔除了最短前缀匹配任何字符(*
),并且匹配任何字符的最短前缀是空字符串。
${arg##/*/}
- 剥离最长前缀匹配图案/*/
- 是无用在此上下文中,因为输出路径将是./
-prefixed由于使用find .
,所以不会有前缀开始/
。相反,${arg##*/}
将工作并剥离父路径(仅保留文件夹名称组件)。
除了它是ill-advised to parse command output in a for
loop,作为@JoSo指出, 在OP的find
命令过于复杂和低效 (顺便说一句,我只想澄清,该find
命令列出当前文件夹的子树的所有文件夹,而不仅仅是眼前的子文件夹):
find . -type d -exec ls -d {} \;
可以简化为:
find . -type d
这两个命令也是这样做的:-exec ls -d {} \;
只是简单地做了默认的find
(暗示-print
)。
如果我们把它放在一起,我们得到:
find . -mindepth 1 -type d | while read -r arg
do
echo "Folder name: ${arg##*/}"
echo "Parent path: ${arg%/*}"
done
请注意,我用${arg%/*}
作为第二输出项目,这条最短后缀匹配/*
,从而返回父路径;此外,我已经添加-mindepth 1
使find
还不匹配.
@JoSo,在注释中,演示了一个解决方案,它更简单,更高效;它采用-exec
处理一个shell命令行和+
到尽可能多的路径在一次传递尽可能:
find . -mindepth 1 -type d -exec /bin/sh -c \
'for arg; do echo "Folder name: ${arg##*/}"; echo "Parent: ${arg%/*}"; done' \
-- {} +
最后,如果你有GNU find
,事情变得更容易,因为你可以利用的-printf
初级,它支持的占位符之类的文件名和父路径:
find . -type d -printf 'Folder name: %f\nParen path: %h\n'
下面是基于通配(路径扩展)一个的bash-唯一的解决方案,礼貌@AdrianFrühwirth的:
买者:这需要bash 4+
,与外壳选项globstar
开启(shopt -s globstar
) - 这是默认关闭。
shopt -s globstar # bash 4+ only: turn on support for **
for arg in **/ # process all directories in the entire subtree
do
echo "Folder name: $(basename "$arg")"
echo "Parent path: $(dirname "$arg")"
done
请注意,我使用basename
和dirname
这里解析,因为他们方便忽略终止/
的水珠**/
不约而同地增加了它的匹配。
的再思考再处理find
的输出在while
循环:上关的机会,你的文件名包含嵌入\n
字符,你可以分析如下,使用空字符。以单独项目(见为什么-d $'\0'
而非-d ''
评论时):
find . -type d -print0 | while read -d $'\0' -r arg; ...
'-d $'\ 0''并不存在。尽管'read'是内置的,它具有传递参数的'argv'(C语言)语义(就像外部程序一样,这是一件好事)。 C字符串不能有NUL字符。它和'-d'''(一个长度为零的字符串)真的是一样的,它恰好因为特定的bash实现而发挥作用。 –
你真正想要什么(如果有的话)是'find -type d -exec/bin/sh -c'arg = $ 1;回声“文件夹:$ {arg ## * /}”; echo“Parent:$ {arg ##%/ *}”' - {} \;''这很复杂 –
或者,对于arg中的“$ @ find -type d -exec/bin/sh -c' “;做回声“文件夹:$ {arg ## * /}”;回声家长:$ {arg ##%/ *};完成'' - {} +' –
${arg##/*/}
是 “参数扩展” 的应用。 (在shell的手册中搜索这个术语,例如在linux shell中键入man bash
)。它扩展为arg
,而没有与/*/
匹配的arg的最长前缀作为全局模式。例如。如果arg
是/foo/bar/doo
,则它扩展到doo
。
这是不好的shell代码(类似于Bash Pitfalls上的项目#1)。 {} \;
与shell没有多大关系,但更多的是find
命令期望的-exec
子命令。 {}
被替换为当前文件名,例如,这导致find
执行命令ls -d FILENAME
,FILENAME将其替换为找到的每个文件。 \;
充当-exec
参数的终止符。参见手册页find
,例如在linux shell上键入man find
,然后查找字符串-exec
以查找说明。
你说得对,以为我误解了它,删除了评论。 – BroSlow
您应该添加周围的代码段反引号(见我的编辑),或者你的问题与格式(包括未显示的字符) –
'$ {如果arg没有以'/'开始,并且/或者包含至少2个'/'(即如果/ * /'不匹配,arg#} *'只会匹配'$ {arg ##/* /}字符串) – BroSlow
你明显从来没有因为shell脚本而感到沮丧,在凌晨3点不起作用。 –