我不知道任何PowerShell,但我知道如何搜索,复制和粘贴。我认为以下命令将运行" git gc"对于git repos的所有子目录。
dir -recurse -include .git | %{ git -C "$_.FullName\.." gc }
有什么问题吗?
我正在使用" git -C"设置要运行的目录的功能。如何在特定目录中执行命令?
答案 0 :(得分:3)
% { Set-Location $_.FullName; git gc }
或
% { Start-Process git -WorkingDirectory $_.FullName -ArgumentList gc -NoNewWindow -Wait}
第一个变体将更改您当前的工作目录,因此请注意这一点。
答案 1 :(得分:0)
<强> TL;博士强>:
字符串插值损坏:
dir -recurse -directory -force -filter .git | % { git -C "$($_.FullName)\.." gc }
也就是说,只需在$_.FullName
中将$(...)
括在双引号字符串中即可解决问题(另外将-Force
添加到dir
({{1} })确保它找到隐藏的Get-ChildItem
子目录;
添加.git
以限制与目录的匹配,并且不是严格需要使用-directory
而不是-filter
,但可以提高性能。
了解双引号字符串中-include
的必要性一般很重要 - 请参阅下文。
对于手头的任务,以上是一个简单,强大且高效的解决方案:通过$(...)
选项将所需目录定位到git
,而无需更改呼叫会话&# 39; s当前目录。
在调用命令之前更改为其他目录:
4c74356b41's answer通过关注OP问题的第二部分来解决问题 - 如何在调用命令之前更改到其他位置 - 同时避免损坏的字符串插值(-C
)。但是,它们(第一个)解决方案是有效的,因为"$_.FullName\.."
也通过其git
子文件夹识别存储库,因此.git
部分引用父目录。不需要。
但是,他们的第一个命令具有更改会话的当前目录的副作用,并且最好避免\..
这样的控制台应用程序使用Start-Process
cmdlet。
请参阅本文的底部以获得解释和更健全的习语。
在git
内扩展$_.FullName
(双引号字符串)将无法正常工作:因为您正在访问属性"..."变量引用的对象,必须将表达式括在子表达式运算符,$_
中,如下所示:
$(...)
顺便说一下:在你的情况下,你实际上根本不需要字符串插值,因为"$($_.FullName)\.."
也通过其git
子文件夹识别了一个repo,因此.git
组件引用父目录。不需要;直接引用\..
就足够了:
$_.FullName
... | % { git -C $_.FullName gc }
如何展开(插值),为什么会被破坏?
管道变量"$_.FullName\.."
通过调用值$_
方法自行扩展 。
.ToString()
是$_
类型的实例,并且在其上调用[System.IO.DirectoryInfo]
会产生给定目录的名称,而不是其路径(例如,如果.ToString()
代表$_
,则C:\Users\jdoe
扩展为"$_"
)。 joe
被解释为字符串的 literal 部分。
我们说.FullName\..
代表目录$_
;因此,C:\Users\jdoe
扩展到以下内容,这显然不是意图:
"$_.FullName\.."
换句话说:在双引号字符串中, jdoe.FullName\..
不会被识别为单个表达式,除非它包含在子表达式运算符$_.FullName
中。 / p>
字符串的更正形式$(...)
然后产生预期结果:
"$($_.FullName)/.."
以下是您可以按原样运行的测试命令,用于说明差异:
C:\Users\jdoe\..
dir -recurse $HOME | % { "$_.FullName\.." } | Select -First 2 # WRONG
有关管理PowerShell的字符串插值(扩展)的规则的完整讨论,请参阅我的this answer。
此外,PowerShell(一般来说是Windows)处理文件系统路径的一个怪癖可能会掩盖你的情况下字符串插值的问题:
将dir -recurse $HOME | % { "$($_.FullName)\.." } | Select -First 2 # OK
附加到不存在的路径组件仍然会产生有效路径 - 这两个组件会有效地相互抵消。
如果我们使用上面的string-interpolation-gone-wrong示例:
\..
是一个有效的 no-op ,因为PowerShell lexically 断定您指的是当前目录(假设Set-Location jdoe.FullName\..
是一个 relative 路径),即使没有名为jdoe.FullName\..
的子目录。
因此,在使用这样的事情的背景下:
jdoe.FullName
... | % { Set-Location "$_.FullName\.."; git gc }
命令无效,所有Set-Location
次调用都在当前目录中运行。
对于控制台(命令行)实用程序的同步调用,例如git
,以下技术是最佳选择:
git
请注意dir -recurse -directory -force -filter .git | % { pushd $_.FullName; git gc; popd }
来电是夹在git
(pushd
)和Push-Location
(popd
)来电之间,确保呼叫会话的当前位置最终不会改变。
注意:如果在Pop-Location
调用后发生终止错误,则当前位置仍会更改,但请注意调用外部实用程序永远不会导致在终止错误时(只有PowerShell本机调用和.NET框架方法可以生成终止错误,可以使用pushd
或try ... catch
语句处理)。
Start-Process
及其trap
参数是以下方案中的正确工具:
显式在新控制台窗口中运行命令
-WorkingDirectory
在当前用户的主目录中异步打开新的Start-Process cmd -WorkingDir $HOME
控制台(&#34;命令提示符&#34;)。启动具有特定工作目录的GUI应用
cmd.exe
异步启动记事本,将当前用户的主目录设置为工作目录注意:
Start-Process notepad.exe -WorkingDir $HOME
异步,这意味着它启动指定的命令,但不会等待< em>完成,然后返回到PowerShell提示符(或继续执行脚本中的下一个命令)
如果您确实要等待以终止进程(通常在窗口关闭时发生),请添加Start-Process
。
使用-Wait
在当前控制台窗口中运行 console 应用程序通常没有意义(没有Start-Process -NoNewWindow -Wait
,输出会到达异步,因此在控制台中无法预测:
调用的控制台应用程序无法连接到当前会话的输入和输出流,因此它不会从PowerShell管道接收输入,并且其输出赢得了&#39 ; t被发送到PowerShell的成功和错误流(这意味着您无法通过管道发送输出或使用-Wait
或>
捕获输出;但是,您可以发送< em> file 作为>>
的输入,类似地,使用-RedirectStandardInput
和-RedirectStandardOutput
此外,直接调用不仅在语法上更简单(比较-RedirectStandardError
到git gc
),而且明显更快。
将Start-Process gc -ArgumentList gc -NoNewWindow -Wait
与控制台应用程序一起使用的唯一方案是:(a)在新的控制台窗口中启动它(省略Start-Process
),(b)运行它作为不同的用户(使用-NoNewWindow
和-Verb
参数),或(c)在原始环境中运行(使用-Credential
)。
最后, Start-Job
是正确的工具:
异步启动无UI(非交互式)后台进程
-UseNewEnvironment
;注意如何在定义要运行的后台命令的脚本块Start-Job { Set-Location $HOME; $PWD }
中显式设置工作目录; { ... }
才能获得后台命令的输出。答案 2 :(得分:0)
dir -recurse -directory -force -filter .git | % {
pushd "$($_.FullName)\.."
write-output '___'
$_.FullName
git count-objects -vH
git submodule foreach --recursive git count-objects -vH
git gc
git submodule foreach --recursive git gc
git count-objects -vH
git submodule foreach --recursive git count-objects -vH
write-output '___'
popd
}
更加详细,也可以处理子模块。