4

I'm trying to do a replace string operation on all files except those in .git folder and all pycache directories which can appear nested in any nested directory. I'm executing the script in the root directory that contains a .git folder.

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!
        )
    )
)

But I am stuck in the if condition of this loop which still prints out all files in the .git folder even though it is excluded using if not "%%~dpF"==".git\". Why? I can't find any solution to this, not even chat gpt can tell me. How is that even possible that the AI doesn't know this? Also if not "%%~dpF"=="%CD%\.git\" does not work.

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

which still prints out the files in the .git folder and __pycache__ folders. This is so easy to achieve using 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

So I don't understand why is it so complicated on windows .bat files to do the same? What gives?

2 Answers2

6

This is not full answer. Only an example using PowerShell.

Save it to a file with extension .ps1. Ex: test.ps1, and place it in your working directory. To Execute, Right Click > Run with PowerShell.

  • Official Format
$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 

This will displays all files and directories except in filter $WL1 $WL2

You can add a file or folder to be excluded by its extension in $WL1, and by its name in $WL2.

  • Short Format
$WL1='.bat','.png','.sh','.ps1'
$WL2='.git','__pycache__'
Pushd $PSScriptRoot
GCI -R|? Name -notin $WL2|? Extension -notin $WL1|% Name
pause 

To Check All available filters, you can type Get-ChildItem -Recurse | Get-Member or GCI -R|GM in PowerShell Console in the directory.

Mr.Key7
  • 957
-1

While PowerShell scripts are vastly easier to write and read than your average batch script, they lack one thing: It's quite hard for your average user to execute them, since you can't just double click them.

There are easy solutions though, with the two most common ones being:

The easy one

Write your PowerShell script as normal. Then create a cmd script in which you put powershell.exe -ExecutionPolicy Bypass -NoProfile -NoLogo -File "%~dp0\MyPowerShellFile.ps1. Now you can give your users both files and they can just double click the bat file as they're used to and it'll execute the powershell script.

This gets you the easy for users (and yourself) to use batch file, while getting all the power of PowerShell. The downside is you now have two files, which brings us to:

One file only

Similar to the previous one, but instead of calling a separate file, you can also integrate your whole script in the batch file and avoid the need for two files.

You can do this by using the -EncodedCommand parameter to pass a base64 encoded string to PowerShell which will contain your whole script.

A simple PowerShell function (have fun writing the equivalent code in cmd..) that takes any PS1 file and creates a bat file is the following:

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
}

}

Source because I don't have my script collection at hand - but looks right.

Voo
  • 138
  • 2
  • 8