这是一个简化的代码,如果目录包含与父目录和扩展名相同的文件名,则打印目录的名称.md
。
FIND(){
find . -type d -exec sh -c '
for d do
[ -f "${d}/${d##*/}.md" ] && printf "%s\n" "$d"
done' find-sh {} +
}
FIND
概括而言,我想将搜索词${d}/${d##*/}.md
作为参数发送给FIND
函数,但不幸的是这不会输出任何内容:
FIND(){
local SearchTerm="${1}"
find . -type d -exec sh -c '
for d do
[ -f "${SearchTerm}" ] && printf "%s\n" "$d"
done' find-sh {} +
}
FIND '${d}/${d##*/}.md'
我确信引用的内容存在一些问题SearchTerm
。有什么提示吗?
我尝试过:FIND '\${d}/\${d##*/}.md'
但没有输出
答案1
"${SearchTerm}"
需要在 之外才能sh -c '
进行推断,如下所示:
FIND(){
local SearchTerm="${1}"
find . -type d -exec sh -c '
for d do
[ -f "'"${SearchTerm}"'" ] && printf "%s\n" "$d"
done' find-sh {} +
}
FIND '${d}/${d##*/}.md'
为了进一步解释一下,我们可以运行一个小测试:
SearchTerm='${d}/${d##*/}.md'
echo 'Before "$SearchTerm" After'
# output : Before "$SearchTerm" After
echo 'Before "'"$SearchTerm"'" After'
# output : Before "${d}/${d##*/}.md" After
'Before "$SearchTerm" After'
是一个没有任何参数扩展的单个字符串,因为它全部用单引号引起来。
'Before "'"$SearchTerm"'" After'
实际上是三个字符串连接在一起:
'Before "'
# 最后,它是一个双引号,后面跟着一个单引号
"$SearchTerm"
# 参数扩展发生在这里。
'" After'
# 开头是单引号,后面是双引号
希望它更清楚。
答案2
您调用的内联脚本是单引号的(应该如此)。这意味着sh -c
shell 将获得一个未展开的脚本"${SearchTerm}"
。由于该 shell 没有SearchTerm
变量,因此它的值将为空。
既然你用标签标记了你的问题巴什,您可以传递导出函数的名称:
# Our find function.
# Takes the name of a test function that will be called
# with the pathname of a directory.
myfind () {
local thetest="$1"
# Run find, passing the name of the function into the in-line script.
find . -type d -exec bash -c '
testfunc=${1:-:}; shift
for dirpath do
"$testfunc" "$dirpath" && printf "%s\n" "$dirpath"
done' bash "$thetest" {} +
}
# Our test function.
test_md_file () {
[ -f "$1/${1##*/}.md" ]
}
export -f test_md_file
# Run the thing.
myfind test_md_file
testfunc=${1:-:}
代码中的会分配$1
给testfunc
是否可用且不为空,否则,它将用作:
测试(返回 true 的无操作实用程序)。
答案3
一些能够运行任意 shell 代码而不仅仅是运行的替代方法[ -f "$d/${d##*/}.md" ]
:
将 shell 代码作为第一个参数传递并用于eval
解释它:
FIND(){
find . -type d -exec sh -c '
code=$1; shift
for d do
eval "$code" && printf "%s\n" "$d"
done' find-sh "$1" {} +
}
FIND '[ -f "$d/${d##*/}.doc" ]'
与环境变量相同
FIND(){
CODE=$1 find . -type d -exec sh -c '
for d do
eval "$CODE" && printf "%s\n" "$d"
done' find-sh "$1" {} +
}
FIND 'base=${d##*/}; [ -f "$d/$base.md" ] && [ -f "$d/$base.doc" ]'
如果要解释的 shell 代码始终是[ -f "something" ]
:
FIND(){
FILE_TEST=$1 find . -type d -exec sh -c '
for d do
eval "[ -f \"$FILE_TEST\" ]" && printf "%s\n" "$d"
done' find-sh "$1" {} +
}
FIND '$d/${d##*/}.doc'
请注意,如果使用zsh
,则可以仅使用其glob 限定符通过任意 shell表达式e
进一步限定目录 ( ) :/
e
print -rC1 ./**/*(ND/e['[ -f $REPLY/$REPLY:t.md ]'])
或者用一个函数:
has_md() [ -f $REPLY/$REPLY:t.md ]
print -rC1 ./**/*(ND/+has_md)
(N
for nullglob
, D
fordotglob
不忽略隐藏文件和目录)