当通过一个文件夹循环
for f in $path
Run Code Online (Sandbox Code Playgroud)
我遇到了意外的行为,即即使没有文件与通配符匹配,仍然会进入循环。我正在使用 cygwin,这是我的代码
#!/bin/sh
here=$(pwd)
release(){
release="$1"
targetdisk="$2"
package="$3"
searchPath="../$package/${package}Setup/*/*/*.msi"
echo $searchPath
ls $searchPath
for f in $searchPath; do
mode=$(echo $file | sed -e 's:.*/.*/\(.*\)/.*\.msi:\1:')
version=$(echo $file | sed -e 's:.*/\(.*\)/.*/*.\.msi:\1:')
PREVIOUSIFS=$IFS
IFS=#
targetPath="$targetdisk:\\Software and tools\\Install\\$release"
newFile="$targetPath\\$package-$mode-$release.exe"
if [ ! -d "$targetPath" ]; then
mkdir -p "$targetPath"
fi
echo $newFile
echo $f
#cp $file $newFile
IFS=$PREVIOUSIFS
done;
}
release $1 $2 MyStuff
Run Code Online (Sandbox Code Playgroud)
我故意放置了不存在的 MyStuff:
$ ./release.sh 1.0-dev G
../MyStuff/MyStuffSetup/*/*/*.msi
ls: ../MyStuff/MyStuffSetup/*/*/*.msi: No such file or directory
G:\Software and tools\Install\1.0-dev\MyStuff--1.0-dev.exe
../MyStuff/MyStuffSetup/*/*/*.msi
Run Code Online (Sandbox Code Playgroud)
但是,正如您所看到的,执行了两个回声。为什么即使没有匹配也会发生这种情况?
与任何文件都不匹配的通配符模式不展开。目的是允许向包含通配符但不打算作为模式的命令键入参数。这在命令行上有点意义,它允许偶尔保存两个引号字符。在脚本中,这很烦人。不幸的是,在传统的 sh 中没有办法改变这种行为。您可以检查图案是否未展开。
for f in "../$package/${package}Setup"/*/*/*.msi; do
if [ "$f" = "../$package/${package}Setup"/*/*/*.msi" ]; then
# No match
break
fi
…
done
Run Code Online (Sandbox Code Playgroud)
可以指示 Bash 将不匹配的通配符模式扩展到空列表。将您的 shebang 行更改为#!/bin/bash,您可以执行以下操作:
shopt -s nullglob
for f in "../$package/${package}Setup"/*/*/*.msi; do
…
Run Code Online (Sandbox Code Playgroud)
您的脚本中还有其他问题。您使用的方式searchPath,如果有空格或通配符(包括反斜杠)变量将打破$package。不要让$searchPath变量替换不加引号。始终在变量替换周围使用双引号,除非您希望它们被视为以空格分隔的模式列表,这里不是这种情况 - $package是一个字符串(需要双引号),而明显地*使很多成为通配符模式。将模式直接放入for循环中,如上。
对于日志记录,而不是这些echo命令(在变量替换周围缺少双引号,因此参数将被破坏),用于set -x在执行时在 stderr 上显示每个命令。
在脚本中的某个时刻,您正在设置IFS=#,但您从未对 进行任何拆分#。IFS如果您不打算使用它,请不要设置。
有几个问题mode=$(echo $file | sed -e 's:.*/.*/\(.*\)/.*\.msi:\1:')。如上所述,它周围缺少双引号"$file"。此外,sed为每个要处理的文件调用额外的程序很慢(在 Cygwin 上执行外部进程很慢)并且过于复杂。Shell 具有字符串处理结构;虽然它们是原始的,但在这里已经足够了。您的
dir="${file%/*}"
mode="${dir##*/}"
dir="${dir%/*}"
version="${dir##*/}"
Run Code Online (Sandbox Code Playgroud)
这个脚本有一堆问题,但你问的行为,为什么循环执行,是这样的:
在外壳构造中
for f in <expr>; do <commands>; done
Run Code Online (Sandbox Code Playgroud)
文件模式通常用于“expr”,然后将其替换为 shell 文件名通配符,这就是您所做的。但是您的表达式不匹配任何内容,因此 globbing 不会将其扩展为文件路径列表。但它也不是像许多其他语言一样的零长度(空)列表,而是带有星号的路径表达式,您在循环上方回显。因此循环执行一次,$f 设置为等于以 *.msi 结尾的未扩展字符串。您可以在循环之前将其回显的位置看到这一点。我们知道这不匹配,因为您也将它与 ls 一起使用,这就是您收到“没有此类文件或目录”错误的原因。
(另请注意,您在循环中使用 $file,我认为您的意思是在那里使用 $f。
| 归档时间: |
|
| 查看次数: |
2007 次 |
| 最近记录: |