我将与你提到的两倍,工作在Windows批处理文件开始。最大的区别是,在Windows上,外壳不作任何通配,把它留给各种命令(和他们每个人做不同的看法),而在Linux/Unix文件名匹配通常是由壳做的,可通过引用或转义来阻止。同时在Windows方法和Linux的做法有其优点,和他们比较不同在不同的使用情况。
对于经常bash用户,报价
./do-for.sh repo-'*' git commit -a -m "Added new files."
或逃避
./do-for.sh repo-\* git commit -a -m "Added new files."
是最简单的解决方案,因为他们是什么,他们每天都在坚持使用。如果用户需要不同的语法,你迄今提出的所有的解决方案,我将分为四类提出我自己的(请注意,在下面do-for.sh
为各自例如为不同脚本采取相应的解决方案之前,它可以在其他答案中找到)
这工作,类似于与其他shell命令类似的情况下采取的解决办法,只有当你的目录名的扩展包括目录名称完全失败等于所述分离器(一个不太可能的情况,这不会在上面的例子中发生的,但在一般情况可能会发生。)
这工作,但同样,它涉及到报价,甚至可能嵌套,并且没有一点在它宁愿更常规的引用通配的字符。
,并考虑待处理目录,直到你打一个名字是不是一个目录。这在很多情况下都会起作用,但可能会以模糊的方式失败(例如,当您拥有一个与命令类似的目录时)。
我的解决方案不属于任何提及的类别。事实上,我建议不要在脚本的第一个参数中使用*
作为通配符。 (这与split
命令使用的语法类似,您可以为要生成的文件提供非全局前缀参数。)我有两个版本(以下代码)。与第一个版本,你会做以下几点:
# repo- is a prefix: the command will be excuted in all
# subdirectories whose name starts with it
./do-for.sh repo- git commit -a -m "Added new files."
# The command will be excuted in all subdirectories
# of the current one
./do-for.sh . git commit -a -m "Added new files."
# If you want the command to be executed in exactly
# one subdirectory with no globbing at all,
# '/' can be used as a 'stop character'. But why
# use do-for.sh in this case?
./do-for.sh repo/ git commit -a -m "Added new files."
# Use '.' to disable the stop character.
# The command will be excuted in all subdirectories of the
# given one (paths have to be always relative, though)
./do-for.sh repos/. git commit -a -m "Added new files."
第二个版本涉及到使用通配符字符外壳一无所知,如SQL的%
字符
# the command will be excuted in all subdirectories
# matching the SQL glob
./do-for.sh repo-% git commit -a -m "Added new files."
./do-for.sh user-%-repo git commit -a -m "Added new files."
./do-for.sh % git commit -a -m "Added new files."
第二个版本是更加灵活,因为它允许非最终的球体,但对于bash世界而言不太标准。
下面是代码:
#!/bin/bash
if [ "$#" -lt 2 ]; then
echo "Usage: ${0##*/} PREFIX command..." >&2
exit 1
fi
pathPrefix="$1"
shift
### For second version, comment out the following five lines
case "$pathPrefix" in
(*/) pathPrefix="${pathPrefix%/}" ;; # Stop character, remove it
(*.) pathPrefix="${pathPrefix%.}*" ;; # Replace final dot with glob
(*) pathPrefix+=\* ;; # Add a final glob
esac
### For second version, uncomment the following line
# pathPrefix="${pathPrefix//%/*}" # Add a final glob
tmp=${pathPrefix//[^\/]} # Count how many levels down we have to go
maxDepth=$((1+${#tmp}))
# Please note that this won’t work if matched directory names
# contain newline characters (comment added for those bash freaks who
# care about extreme cases)
declare -a directories=()
while read d; do
directories+=("$d")
done < <(find . -maxdepth "$maxDepth" -path ./"$pathPrefix" -type d -print)
curDir="$(pwd)"
for d in "${directories[@]}"; do
cd "$d";
"[email protected]"
cd "$curDir"
done
与Windows,你仍然需要如果前缀包含空格
使用引号
./do-for.sh 'repository for project' git commit -a -m "Added new files."
(但如果前缀不包含空格,你可以避免引用它,它将正确处理以该前缀开头的任何包含空格的目录名;有明显的变化,第二个版本中的%-patterns也是如此)。请注意Windows和Linux环境之间的其他相关差异,例如路径名中的区分大小写,字符被认为特殊的区别等等。
请参阅http://mywiki.wooledge.org/Quotes我向你保证它会回答你所有的问题。 – andlrc
用'do-for'*'pwd'引用它。但是如果任何目录的名字中有空格,你的脚本将无法工作。 – Barmar
andlr我相信你的页面是一个很好的参考,但标准的堆栈溢出实践是提供答案;链接是次要的。而Barmar,我不想强迫我的用户添加引号。 –