$ {arg ## / * /}和{} \的含义是什么?在shell脚本中

时间:2014-03-24 22:44:46

标签: shell sh

请找到以下代码,以显示当前文件夹中的目录。

  1. shell脚本中${arg##/*/}的含义是什么? (arg#*arg##/*/都提供相同的输出。)
  2. for loop语句中{} \;的含义是什么。
  3. for arg in `find . -type d -exec ls -d {} \;`
    do
      echo "Output 1" ${arg##/*/}
      echo "Output 2" ${arg#*}
    done
    

2 个答案:

答案 0 :(得分:7)

添加到@ JoSo的有用答案:

${arg#*}从根本上毫无意义的扩展,因为它的结果始终与$arg本身相同,因为它删除最短前缀匹配< em>任何字符(*)和匹配任何字符的最短前缀是空字符串。

${arg##/*/} - 剥离最长的前缀匹配模式/*/ - 在此上下文中无效,因为输出路径为{{1 - 由于使用./而加前缀,因此没有以find .开头的前缀。相比之下,/将工作并剥离父路径(仅保留文件夹名称组件)。

除了ill-advised to parse command output in a for loop,正如@JoSo指出的那样, OP中的${arg##*/}命令过于复杂且效率低下 (另外,为了澄清,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在评论中展示了一种更简单,更高效的解决方案;它使用.来内联处理shell命令,-exec一次传递尽可能多的路径:

+

最后,如果你有GNU find . -mindepth 1 -type d -exec /bin/sh -c \ 'for arg; do echo "Folder name: ${arg##*/}"; echo "Parent: ${arg%/*}"; done' \ -- {} + ,事情变得更加容易,因为你可以利用find主数据库,它支持文件名和父路径之类的占位符:

-printf

这是一个基于globbing(路径名扩展)的 bash-only解决方案,由@AdrianFrühwirth提供:

警告:这需要find . -type d -printf 'Folder name: %f\nParen path: %h\n' ,shell选项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进行解析,因为它们会方便地忽略glob dirname总是添加到其匹配项中的终止/。 / p>


**/循环中重新处理find的输出:如果您的文件名包含嵌入的while字符,则可以使用null char解析如下。分隔项目(请参阅有关使用\n而不是-d $'\0'的原因的评论):

-d ''

答案 1 :(得分:2)

  1. ${arg##/*/}是&#34;参数扩展&#34;的应用程序。 (在shell的手册中搜索这个术语,例如在linux shell中输入man bash)。它扩展为arg,没有与/*/匹配的最长arg前缀作为glob模式。例如。如果arg/foo/bar/doo,则展开为doo

  2. 那个糟糕的shell代码(类似于Bash Pitfalls上的第1项)。 {} \;与shell没什么关系,但更多的是find命令期望-exec子命令的参数。 {}将替换为当前文件名,例如这会导致find执行命令ls -d FILENAME,并将FILENAME替换为它找到的每个文件。 \;充当-exec参数的终止符。请参阅find的手册页,例如在linux shell上键入man find,并在那里查找字符串-exec以查找说明。