Replace text at specific line number with file name

Viewed 81

I have 400+ .vcf files that I would like to replace the "FN:" line (line 4) with the file name. I've looked at multiple solutions and I can't seem to find something that will achieve what I'm looking for even though I know there's a way to do this.

This is what I have currently

File Name: LastNamefirstName

BEGIN:VCARD
VERSION:3.0
N:lastName;firstName;;;
FN:firstName lastName
ADR:;;111 Main Rd;Columbia;MO;65202;
TEL;TYPE=mobile:(111) 222-3333
EMAIL;TYPE=work:email@gmail.com
BDAY:20000101
END:VCARD

This is what I would like to achieve

Keep "FN:" and replace the text after it with the file name text.

BEGIN:VCARD
VERSION:3.0
N:lastName;firstName;;;
FN:LastNamefirstName
ADR:;;111 Main Rd;Columbia;MO;65202;
TEL;TYPE=mobile:(111) 222-3333
EMAIL;TYPE=work:email@gmail.com
BDAY:20000101
END:VCARD

This Powershell script does do half what I want but I would really like to take the file name and input it in the replacementLineText.

# Set by user to their needs.
$filesToCheck = "C:\path\*.vcf"
$lineToChange = 4
$replacementLineText = "New Text"

# Gather list of files based on the path (and mask) provided by user.
$files = gci $filesToCheck

# Iterate over each file.
foreach ($file in $files) {

    # Load the contents of the current file.
    $contents = Get-Content $file

    # Iterate over each line in the current file.
    for ($i = 0; $i -le ($contents.Length - 1); $i++) {

        # Are we on the line that the user wants to replace?
        if ($i -eq ($lineToChange - 1)) {

            # Replace the line with the Replacement Line Text.
            $contents[$i] = $replacementLineText

            # Save changed content back to file.
            Set-Content $file $contents
        }
    }
}

Any input or guidance would be greatly appreciated!

1 Answers

I would really like to take the file name and input it in the replacementLineText.

To accept the paths of all target files, all you need to do is declare a parameter:

param(
  [Parameter(Mandatory = $true)]
  [string[]]$Path
)

$lineToChange = 4

# Gather list of files based on the path (and mask) provided by user.
$files = gci -Path $Path

# ... rest of original script

I made a slight modification to the variable names - Path is the idiomatic parameter name for strings describing expandable paths, and parameter names are generally expected to be upper case.

The Mandatory flag in the [Parameter()] attribute associated with $Path means that the caller MUST supply a value - otherwise PowerShell will prompt for it:

PS C:\> .\script.ps1

cmdlet script.ps1 at command pipeline position 1
Supply values for the following parameters:
Path:

PS C:\> .\script.ps1 -Path "C:\path\*.vcf" # now it won't prompt

For more information on parameters, see the about_Functions and about_Functions_Advanced_Parameters help topics - although the documentation is about functions, the rules for parameters and their declaration is the same for script files (you can think of a script file as a function that happens to sit on the filesystem instead of in memory)


The gci (or Get-ChildItem) cmdlet returns [FileInfo] objects, with all the files metadata, so to use the file name as the replacement value inside the loop, you simply do $file.Name:

$contents[$i] = "FN:$($file.Name)"
# or using the -f format operator:
$contents[$i] = "FN:{0}" -f $file.Name

Since you already know which index (line number minus 1) you want to modify, you can skip the inner loop and instead do:

param(
  [Parameter(Mandatory = $true)]
  [string[]]$Path
)

$lineToChange = 4

# Gather list of files based on the path (and mask) provided by user.
$files = Get-ChildItem -Path $Path

# Iterate over each file.
foreach ($file in $files) {

    # Load the contents of the current file.
    $contents = Get-Content $file

    if($contents.Count -ge $lineToChange){
        # Replace the line with the Replacement Line Text.
        $contents[$lineToChange - 1] = "FN:$($file.Name)"

        # Save changed content back to file.
        Set-Content $file $contents
    }
}
Related