External Links Batch Conversion Guide

Summary


Conversion Patterns & Commands

Pattern Overview

Current format (to replace):

[link text](https://example.com)
[link text](http://example.com)

Target format (new):

[link text](https://example.com){:target="_blank" rel="noopener noreferrer"}
[link text](http://example.com){:target="_blank" rel="noopener noreferrer"}

IMPORTANT: Exclude Pattern

Do NOT replace links that already have this pattern:

{:target="_blank" rel="noopener noreferrer"}

PowerShell Script (Batch Convert All Files)

This is the most reliable method for your Windows environment:

$basePath = "c:\Users\Ajay.Gupt\OneDrive - Reliance Corporate IT Park Limited\Documents\csp\Ajay3007.github.io\learning"

# Get all markdown files
$files = Get-ChildItem -Path $basePath -Filter "*.md" -Recurse

$fileCount = 0
$linkCount = 0

foreach ($file in $files) {
    $content = Get-Content -Path $file.FullName -Raw
    $originalContent = $content
    
    # Pattern: Match external links NOT already containing {:target="_blank"
    # This regex finds [text](url) where url starts with http/https
    # and the closing ) is not followed by {:target="_blank"
    
    $pattern = '\[([^\]]+)\]\((https?://[^)]+)\)(?!\{:target)'
    
    $content = [regex]::Replace(
        $content,
        $pattern,
        {
            param($match)
            $linkText = $match.Groups[1].Value
            $url = $match.Groups[2].Value
            return "[${linkText}](${url}){:target=`"_blank`" rel=`"noopener noreferrer`"}"
        }
    )
    
    if ($content -ne $originalContent) {
        Set-Content -Path $file.FullName -Value $content -Encoding UTF8
        $newLinkCount = ([regex]::Matches($content, '\{:target="_blank"').Count)
        $oldLinkCount = ([regex]::Matches($originalContent, '\{:target="_blank"').Count)
        $converted = $newLinkCount - $oldLinkCount
        
        if ($converted -gt 0) {
            $fileCount++
            $linkCount += $converted
            Write-Host "✓ $($file.Name) - Converted $converted links"
        }
    }
}

Write-Host "`nConversion Complete!"
Write-Host "Files modified: $fileCount"
Write-Host "Total links converted: $linkCount"

How to run:

  1. Open PowerShell
  2. Copy the script above
  3. Paste and execute in PowerShell
  4. Monitor the output for success

Method 2: sed Commands (for Git Bash / WSL)

If you prefer Unix-style tools, use these sed commands:

Single sed Command for Batch Replace

cd "c:/Users/Ajay.Gupt/OneDrive - Reliance Corporate IT Park Limited/Documents/csp/Ajay3007.github.io/learning"

# Convert all .md files in place
find . -type f -name "*.md" -exec sed -i \
  's/\(\[[^]]*\]\)(https\?:\/\/[^)]*)\([^{]*\)$/\1\2{:target="_blank" rel="noopener noreferrer"}/g' \
  {} +

Alternative sed Pattern (More Precise)

# This pattern is more careful about not double-converting
find . -type f -name "*.md" -exec sed -i \
  -E 's/(\[[^\]]+\]\(https?:\/\/[^)]+\))(?!\{:target)/${1}{:target="_blank" rel="noopener noreferrer"}/g' \
  {} +

Per-File sed Command

If you want to process files individually:

sed -i 's/\(\[[^]]*\]\)(https\?:\/\/[^)]*)\([^{]*\)$/\1\2{:target="_blank" rel="noopener noreferrer"}/g' filename.md

Method 3: VS Code Find and Replace

Using VS Code Regex Find & Replace

Step 1: Open Find and Replace

Step 2: Enable Regex Mode

Step 3: Use This Pattern

Find pattern:

\[([^\]]+)\]\((https?://[^)]+)\)(?!\{:target)

Replace pattern:

[$1]($2){:target="_blank" rel="noopener noreferrer"}

Step 4: Replace All


Method 4: Notepad++ (If Using on Windows)

Using Find and Replace in Notepad++

Step 1: Open Find > Replace (Ctrl+H)

Step 2: Settings

Step 3: Patterns

Find:

\[([^\]]+)\]\((https?://[^)]+)\)(?!\{:target)

Replace:

[$1]($2){:target="_blank" rel="noopener noreferrer"}

Step 4: Replace All


Method 5: Node.js Script (Alternative)

If you prefer Node.js:

const fs = require('fs');
const path = require('path');

const basePath = 'c:\\Users\\Ajay.Gupt\\OneDrive - Reliance Corporate IT Park Limited\\Documents\\csp\\Ajay3007.github.io\\learning';

function processMarkdownFiles(dir) {
    const files = fs.readdirSync(dir, { withFileTypes: true });
    let totalConverted = 0;
    let filesModified = 0;

    for (const file of files) {
        const fullPath = path.join(dir, file.name);
        
        if (file.isDirectory()) {
            const result = processMarkdownFiles(fullPath);
            totalConverted += result.count;
            filesModified += result.files;
        } else if (file.name.endsWith('.md')) {
            const content = fs.readFileSync(fullPath, 'utf-8');
            const originalContent = content;
            
            // Pattern: [text](http://... or https://...) not followed by {:target="_blank"
            const pattern = /\[([^\]]+)\]\((https?:\/\/[^)]+)\)(?!\{:target)/g;
            const newContent = content.replace(pattern, 
                '[$1]($2){:target="_blank" rel="noopener noreferrer"}');
            
            if (newContent !== originalContent) {
                const converted = (newContent.match(/\{:target="_blank"/g) || []).length - 
                                (originalContent.match(/\{:target="_blank"/g) || []).length;
                fs.writeFileSync(fullPath, newContent, 'utf-8');
                console.log(`✓ ${file.name} - Converted ${converted} links`);
                filesModified++;
                totalConverted += converted;
            }
        }
    }

    return { count: totalConverted, files: filesModified };
}

const result = processMarkdownFiles(basePath);
console.log(`\nConversion Complete!`);
console.log(`Files modified: ${result.files}`);
console.log(`Total links converted: ${result.count}`);

How to run:

node convert-links.js

Method 6: Plain Regex for Manual Use

If you’re using Find & Replace in any text editor, here are the core patterns:

Regex Pattern (for most tools)

Pattern to find:    \[([^\]]+)\]\((https?:\/\/[^)]+)\)(?!\{:target)
Pattern to replace: [$1]($2){:target="_blank" rel="noopener noreferrer"}

What Each Part Means


Verification Steps

After Conversion, Verify Results

Count converted links:

$basePath = "c:\Users\Ajay.Gupt\OneDrive - Reliance Corporate IT Park Limited\Documents\csp\Ajay3007.github.io\learning"
Get-ChildItem -Path $basePath -Filter "*.md" -Recurse | 
  Select-String -Pattern '\{:target="_blank"' | 
  Measure-Object | 
  Select-Object -ExpandProperty Count

Expected result: Should be around 142 (134 original + 8 already present)

$basePath = "c:\Users\Ajay.Gupt\OneDrive - Reliance Corporate IT Park Limited\Documents\csp\Ajay3007.github.io\learning"
Get-ChildItem -Path $basePath -Filter "*.md" -Recurse | 
  ForEach-Object {
    Select-String -Path $_.FullName -Pattern '\[([^\]]+)\]\((https?://[^)]+)\)(?!\{:target)' | 
    ForEach-Object { $_ }
  }

Expected result: No matches (or very few if there are edge cases)


Quick Start (Copy-Paste Ready)

$basePath = "c:\Users\Ajay.Gupt\OneDrive - Reliance Corporate IT Park Limited\Documents\csp\Ajay3007.github.io\learning"; $files = Get-ChildItem -Path $basePath -Filter "*.md" -Recurse; $fileCount = 0; $linkCount = 0; foreach ($file in $files) { $content = Get-Content -Path $file.FullName -Raw; $originalContent = $content; $pattern = '\[([^\]]+)\]\((https?://[^)]+)\)(?!\{:target)'; $content = [regex]::Replace($content, $pattern, { param($match); $linkText = $match.Groups[1].Value; $url = $match.Groups[2].Value; return "[${linkText}](${url}){:target=`"_blank`" rel=`"noopener noreferrer`"}" }); if ($content -ne $originalContent) { Set-Content -Path $file.FullName -Value $content -Encoding UTF8; $newLinkCount = ([regex]::Matches($content, '\{:target="_blank"').Count); $oldLinkCount = ([regex]::Matches($originalContent, '\{:target="_blank"').Count); $converted = $newLinkCount - $oldLinkCount; if ($converted -gt 0) { $fileCount++; $linkCount += $converted; Write-Host "✓ Converted $converted links" } } }; Write-Host "Done! Files: $fileCount, Links: $linkCount"

Edge Cases to Consider


Summary

Method Tool Complexity Speed Recommended
PowerShell PowerShell Low Fast ✅ YES
sed Git Bash / WSL Medium Very Fast Good
VS Code Text Editor Very Low Medium Good for small sets
Notepad++ Text Editor Low Medium Alternative
Node.js Node.js Medium Fast If JS familiar

Recommendation: Use Method 1 (PowerShell) - it’s native to Windows, safest, and provides good feedback.


Support

If you encounter any issues:

  1. Verify the base path is correct
  2. Ensure you have backup of files
  3. Test on a single file first
  4. Check file encoding (should be UTF-8)
  5. Verify regex engine supports lookahead ((?!...)