我正在尝试对除 .git 文件夹中的文件之外的所有文件执行替换字符串操作,并且所有pycache可以嵌套在任何嵌套目录中的目录。我正在包含 .git 文件夹的根目录中执行脚本。
for /r /d %%F in (*) do (
echo Checking: %%F
if not "%%~xF"==".sh" if not "%%~xF"==".png" if not "%%~xF"==".bat" if not "%%~dpF"=="__pycache__\" if not "%%~dpF"==".git\" (
echo Found file: %%F
findstr /C:"{{ADDON_NAME_PACKAGE}} {{ADDON_NAME}} {{ADDON_NAME_FULL}}" "%%F" >nul 2>&1
if not errorlevel 1 (
echo %%F
set "file=%%F"
setlocal DisableDelayedExpansion
set "cmd=sed -i -e ""s/%replace_package%/%package_name%/g"" -e ""s/%replace_addon_name%/%addon_short_name%/g"" -e ""s/%replace_addon_name_full%/%addon_full_name%/g"" ""!file!""
endlocal & !cmd!
echo Replaced placeholders in !file!
)
)
)
但我被困在如果此循环的条件是,即使使用排除,仍会打印出 .git 文件夹中的所有文件if not "%%~dpF"==".git\"
。为什么?我找不到任何解决方案,甚至聊天 gpt 也无法告诉我。人工智能怎么可能不知道这一点?也if not "%%~dpF"=="%CD%\.git\"
不起作用。
for /r /d %%F in (*) do (
echo Checking: %%F
if not "%%~xF"==".sh" if not "%%~xF"==".png" if not "%%~xF"==".bat" if not "%%~dpF"=="__pycache__\" if not "%%~dpF"==".git\" (
echo Found file: %%F
它仍然会打印出 .git 文件夹和 __pycache__ 文件夹中的文件。使用 Unix/Linux 很容易实现这一点
replace_package="{{ADDON_NAME_PACKAGE}}"
replace_addon_name="{{ADDON_NAME}}"
replace_addon_name_full="{{ADDON_NAME_FULL}}"
perform_replacements() {
local file="$1"
local package_name="$2"
local addon_short_name="$3"
local addon_full_name="$4"
sed -i "s/${replace_package}/${package_name}/g; s/${replace_addon_name}/${addon_short_name}/g; s/${replace_addon_name_full}/${addon_full_name}/g" "$file"
}
find . \( -name .git -o -name __pycache__ \) -prune -o \( -type f -not -name "*.sh" -not -name "*.png" \) -print0 | while IFS= read -r -d '' file; do
perform_replacements "$file" "$package_name" "$addon_short_name" "$addon_full_name"
echo "Replaced placeholders in $file"
done
所以我不明白为什么在 Windows .bat 文件中执行相同操作会如此复杂?这是怎么回事?
答案1
这不是完整的答案。 仅是一个使用 PowerShell 的示例。
将其保存为扩展名为 . 的文件.ps1
(例如:)test.ps1
,并将其放在工作目录中。要执行,Right Click
> Run with PowerShell
.
- 官方格式
$WL1 = @('.bat', '.png', '.sh', '.ps1')
$WL2 = @('.git', '__pycache__')
if ($PWD.Path -ne $PSScriptRoot) {Push-Location -Path $PSScriptRoot}
Get-ChildItem -Recurse | Where {$_.Name -notin $WL2 -and $_.Extension -notin $WL1} |
ForEach-Object {$_.Name}
pause
这将显示除过滤器之外的所有文件和目录$WL1
$WL2
$WL1
您可以在 中按扩展名添加要排除的文件或文件夹,并在 中按名称添加要排除的文件或文件夹$WL2
。
- 短格式
$WL1='.bat','.png','.sh','.ps1'
$WL2='.git','__pycache__'
Pushd $PSScriptRoot
GCI -R|? Name -notin $WL2|? Extension -notin $WL1|% Name
pause
要检查所有可用的过滤器,您可以在目录中的 PowerShell 控制台中键入Get-ChildItem -Recurse | Get-Member
或。GCI -R|GM
答案2
尽管 PowerShell 脚本比普通批处理脚本更容易编写和阅读,但它们缺少一件事:普通用户很难执行它们,因为您不能双击它们。
不过,也有简单的解决方案,其中最常见的两个是:
简单一点
像平常一样编写 PowerShell 脚本。然后创建一个 cmd 脚本,在其中输入powershell.exe -ExecutionPolicy Bypass -NoProfile -NoLogo -File "%~dp0\MyPowerShellFile.ps1
。现在,您可以将这两个文件提供给用户,他们只需像往常一样双击 bat 文件,它就会执行 powershell 脚本。
这样,用户(和您自己)就可以更轻松地使用批处理文件,同时获得 PowerShell 的所有功能。缺点是您现在有两个文件,这将导致:
仅限一个文件
与前一个类似,但不是调用单独的文件,您还可以将整个脚本集成到批处理文件中,从而避免需要两个文件。
您可以使用-EncodedCommand
参数将包含整个脚本的 base64 编码字符串传递给 PowerShell 来执行此操作。
一个简单的 PowerShell 函数(在 cmd 中编写等效代码很有趣..)可以接受任何 PS1 文件并创建一个 bat 文件,如下所示:
function Convert-PowerShellToBatch
{
param
(
[Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
[string]
[Alias("FullName")]
$Path
)
process
{
$encoded = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes((Get-Content -Path $Path -Raw -Encoding UTF8)))
$newPath = [Io.Path]::ChangeExtension($Path, ".bat")
"@echo off`npowershell.exe -NoExit -encodedCommand $encoded" | Set-Content -Path $newPath -Encoding Ascii
}
}
来源因为我手头没有脚本集合-但看起来正确。