Michael
Michael

Reputation: 147

Insert string into multiple filenames

I have multiple files named in this format:

Fat1920OVXPlacebo_S20_R1_001.fastq
Kidney1235SHAM_S65_R1_001.fastq
Kidney1911OVXPlacebo_S94_R2_001.fastq
Liver1289OVXEstrogen_S24_R2_001.fastq

I need to insert the string "L1000_" into their names so that they read

Fat1920OVXPlacebo_S20_L1000_R1_001.fastq
Kidney1235SHAM_S65_L1000_R1_001.fastq
Kidney1911OVXPlacebo_S94_L1000_R2_001.fastq
Liver1289OVXEstrogen_S24_L1000_R2_001.fastq

I apologize but I have absolutely no experience in coding in powershell. The closest thing I could find to do this was a script that renames the entire file:

Set objFso = CreateObject(“Scripting.FileSystemObject”)

Set Folder = objFSO.GetFolder(“ENTER\PATH\HERE”)

For Each File In Folder.Files

    sNewFile = File.Name

    sNewFile = Replace(sNewFile,”ORIGINAL”,”REPLACEMENT”)

    if (sNewFile<>File.Name) then

        File.Move(File.ParentFolder+”\”+sNewFile)

    end if

Next

however, I just need to insert a string at a specific place in the file's title. I have 257 files and do not want to go 1 by 1. Does anyone have an idea on how to run this in windows?

Upvotes: 1

Views: 563

Answers (3)

mklement0
mklement0

Reputation: 440679

Use Get-ChildItem to enumerate the files of interest, pipe them to Rename-Item, and use a delay-bind script block ({ ... }) to dynamically determine the new name, via a regex-based -replace operation.

(Get-ChildItem $yourFolder -Filter *.fastq) |
  Rename-Item -NewName { $_.Name -replace '(?<=_S\d+_)', 'L1000_' } -WhatIf

Note:
• The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.
• Even though not strictly necessary in this case, enclosing the Get-ChildItem command in (...), the grouping operator ensures that already renamed files don't accidentally re-enter the enumeration of files to be renamed - see this answer.

  • (?<=_S\d+_) uses a positive look-behind assertion ((?<=...)) to match verbatim string _S, followed by one or more (+) digits (\d), followed by verbatim _.

  • Since the look-behind assertion merely matches a position in the string rather than a substring, the replacement operand, verbatim L1000_ in this case, is inserted at that position in (a copy of) the input string.

  • For a more detailed explanation of the delay-bind script-block technique, see this answer.

Upvotes: 6

Bill_Stewart
Bill_Stewart

Reputation: 24585

Using PowerShell, you could use a regular expression to rename the files. Example:

Get-ChildItem "C:\foldername\here\*.fastq" | ForEach-Object {
  $oldName = $_.Name
  $newName = [Regex]::Replace($oldName,'(S\d+)_(R\d+)','$1_L1000_$2')
  Rename-Item $_ $newName -WhatIf
}

[Regex] is a PowerShell type accelerator for the .NET Regex class, and Replace is the method for the Regex class that performs text substitutions. The first parameter to the Replace method is the input string (the old filename), the second parameter is the regular expression pattern (run help about_Regular_Rxpressions for more information), and the third parameter is the replacement string pattern, where $1 is the first capture pattern in ( ), and $2 is the second capture pattern in ( )). Finally, the Rename-Item cmdlet renames the files. Remove the -WhatIf parameter if the output looks correct to actually perform the renames.

Upvotes: 0

Lee_Dailey
Lee_Dailey

Reputation: 7489

here's one way to do that with PoSh. note that the demo does not handle either the rename or directory related stuff. it ONLY handles generating the new file names.

what it does ...

  • fakes reading in a list of fileinfo objects
    when ready to do this for real, replace the entire #region/#endregion block with a call to Get-ChildItem and save it to $FileList.
  • sets the text to be inserted
  • iterates thru the file list
  • splits the file .Name property on the underscores
  • saves that to a $Var
  • adds the 1st two splits, the insertion text, and the last two splits to a new array
  • joins that array with an underscore as the delimiter
  • sends the new file name to the $Result collection
  • displays the list of new names

the code ...

#region - fake reading in a list of files
#    in real life, use Get-ChildItem
$FileList = @(
    [system.io.fileinfo]'Fat1920OVXPlacebo_S20_R1_001.fastq'
    [system.io.fileinfo]'Kidney1235SHAM_S65_R1_001.fastq'
    [system.io.fileinfo]'Kidney1911OVXPlacebo_S94_R2_001.fastq'
    [system.io.fileinfo]'Liver1289OVXEstrogen_S24_R2_001.fastq'
    )
#endregion - fake reading in a list of files


$InsertionText = 'L1000'

$Result = foreach ($FL_Item in $FileList)
    {
    $FLI_Parts = $FL_Item.Name.Split('_')
    ($FLI_Parts[0,1] + $InsertionText + $FLI_Parts[2,3]) -join '_'
    }

$Result

output ...

Fat1920OVXPlacebo_S20_L1000_R1_001.fastq
Kidney1235SHAM_S65_L1000_R1_001.fastq
Kidney1911OVXPlacebo_S94_L1000_R2_001.fastq
Liver1289OVXEstrogen_S24_L1000_R2_001.fastq

Upvotes: 1

Related Questions