birdcage
birdcage

Reputation: 2676

Renaming files in a directory with a list in Text file

I have a folder with thousands of files and I don't have a list of names of these files. They are just random.

asd.wav
faf.wav
gwa.wav

And I have a FileNames.txt with the names of files:

1A
2
3
4B

I just want to rename my files with the order of file names in txt file. Number of lines in the txt can be more or less. It should just stop renaming when it comes to end of lines. How to do that?

Upvotes: 2

Views: 5135

Answers (4)

FFR
FFR

Reputation: 1

here is how I did it:

$FileNo = 0
$date = (get-date).ToString('yyyyMMdd')
Get-ChildItem -LiteralPath 'C:\YourFilePath\' -File | ForEach-Object {
        $_ | Rename-Item -NewName { "something" + $date + "_" + $FileNo + ($_.Extension) }
        $FileNo++
    }

for the counter you could read out the file/csv and add a counter to jump though the rows (you can also leave out the date, thats just something I added)

Upvotes: 0

Mark
Mark

Reputation: 4453

Here's a bash answer:

ls  | paste - FileNames.txt   | awk 'NF == 2 { print "mv ", $1, $2 } ' | bash

To be honest, the solution is a little dangerous - spaces in file names (in FileNames.txt or in the directory) will cause issues.

Here's a more robust version that handles spaces and even filenames with $:

awk ' 
  FNR == NR { filename[ ++count ] = $0 ;  next }
  count > 0 { printf( "mv '"'%s' '%s'"'\n", $0, filename[ count-- ])  } 
' FileNames.txt <( ls )  | bash

Upvotes: 2

mklement0
mklement0

Reputation: 439297

PowerShell solutions:

PowerShell 7+ solution:

[Linq.Enumerable]::Zip(
  [string[]] (Get-ChildItem . -File).FullName,
  [string[]] (Get-Content FileNames.txt) 
) | Rename-Item -LiteralPath { $_.Item1 } -NewName { $_.Item2 } -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.

The above uses . to target files in the current directory; adapt as needed.

The System.Linq.Enumerable.Zip method allows convenient enumeration of pairs of collection elements, as 2-element tuples; note that the arguments must be explicitly typed with casts ([string[]]) in order for PowerShell to resolve the method call correctly; generally, note that PowerShell, as of 7.0, lacks support for .NET extension methods (which requires explicit use of [System.Linq.Enumerable] here) and comprehensive support for calling generic methods, though there are feature requests on GitHub - see here and here.

These tuples are piped to Rename-Item, whose parameters are bound via delay-bind script blocks to dynamically access each input tuple's properties.


PowerShell 6- solution:

# Read the array of lines == new file names from FileNames.txt
$names = Get-Content FileNames.txt

# Get as many files as new file names; '.' targets the current directory;
# Adapt as needed.
$files = (Get-ChildItem . -File)[0..($names.Count-1)] 

# Perform the renaming.
$i = 0
$files | Rename-Item -NewName { $names[$script:i++] } -WhatIf 

Note: The $i variable is referred to as $script:i in the delay-bind script block ({ ... }), because the script block runs in a child scope. To make this also work in cases where the parent scope isn't also the script scope, use (Get-Variable -Scope 1 i).Value++ instead of $script:i++.

Upvotes: 3

jacouh
jacouh

Reputation: 8741

I've worked out another PowerShell script:

In the currenct working directory ./, we create a script named ./renamedir1.ps1. And we have a subdirectory ./subdir2handle, and the new file names list is in the file ./fileslist.txt.

This arrangement can avoid affecting files renamedir1.ps1 and fileslist.txt themselves.

renamedir1.ps1 here:

#
# define some vars:
#
$myDir2Handle = "subdir2handle"
$myFilesList = "fileslist.txt"

#
# get files list in dir subdir2handle:
#
$xarr = (Get-ChildItem $myDir2Handle).name
$nx = $xarr.length

#
# get list file content in another array:
#
$yarr = Get-Content $myFilesList
$ny = $yarr.length
#$yarr[0]
#exit(0);

#
# get minimum of the 2 lengths:
#
$nMin = [math]::min($nx, $ny)

#
# rename items:
#
for($i = 0; $i -lt $nMin; $i++) {
    Write-Host Rename $xarr[$i]
    Move-Item ($myDir2Handle + "/" + $xarr[$i]) ($myDir2Handle + "/" + $yarr[$i])
}

In Windows, we invoke the script by:

.\renamedir1.ps1

Upvotes: 2

Related Questions