Remove something from the name of a lot of files? - powershell

I have a lot of files named like
Files_01(some text).png
Files_02(some different text).png
Files_03(some other text).png
Files_04(totally different text).png
What I'm looking for is a way to remove everything in the brackets so that I'm left with:
Files_01.png
Files_02.png
etc.
I tried the following, but it didn't remove the text in parentheses:
Get-ChildItem .png | foreach {
Rename-Item $_ $_.Name.Replace("()", "")
}

This is how I completed the task. I read in the file objects from the directory, then check if the filename contains parentheses. If the name does, I replace the parentheses and any text in between with an empty string. Then call Rename-Item and pass it the new file name without the parentheses.
Get-ChildItem -Path C:\PowershellTest\ | % {if($_.Name -match '.*\(.*\).*') {Rename-Item -Path $_.FullName -NewName $($_.Name -replace '\(.*\)', '')}}

Try like this :
#echo off
set "$ext=.png"
for /f "delims=" %%b in ('dir /b/a-d *%$ext%') do for /f "tokens=1 delims=()" %%c in ('echo %%b') do ren "%%~nb%$ext%" "%%~nc%$ext%"

In powershell I'd probably create something like this:
$myFolder = "C:\Users\Aarron\Pictures\"
Foreach ($file in Get-Childitem $myFolder\*.png)
{
$ReName = $file.basename.split("(")[0] + $file.extension
Rename-Item $file.FullName $ReName
}
…and a possible batch solution:
#Echo Off
Set "myFolder=C:\Users\Aarron\Pictures\"
For %%A In ("%myFolder%\*.png") Do Call :Sub "%%~dpA" "%%~nA" "%%~xA"
Exit/B
:Sub
Set "ReName=%~2"
Set ReName=%ReName:(=&:%
Ren "%~1%~2%~3" "%ReName%%~3"

Related

Batch/Powershell: if files have the same compound words of folders, move them to the folder that have the same string

I have some folders like
Computer Idea
confidenze fatali
Casa Naturale sette
and files like
2021-09-01 computer idea.rar
into confidenze fatali.pdf
casa naturale sette 454.jpg
I try to move in this way
Computer Idea
|
|---> 2021-09-01 computer idea.rar
confidenze fatali
|
|---> into confidenze fatali.pdf
Casa Naturale sette
|
|---> casa naturale sette 454.jpg
For example, composed word computer idea is found for both 2021-09-01 computer idea.rar file and Computer Idea folder (in this situation we have same 2 adjacent words). Delimitator for composed word is simply an empty space.
I try to use this batch script but doesn't work, I ask also for a powershell solution so I add that tag in question.
#Echo off
Pushd %1
For /d %%A in (*) do For /f "delims=" %%B in (
'Dir /B "*%%~nxA*" 2^>Nul '
) do If "%%~nxA" NEQ "%%~nxB" Move "%%~fB" "%%~fA\" 2>&1>>Nul
Popd
With PowerShell you do:
$rootFolder = 'D:\Test'
# get a list of folders inside the root folder
$subFolders = Get-ChildItem -Path $rootFolder -Directory
# next loop through the folders and find files that match their names
foreach ($folder in $subFolders) {
# use the foldername as filter, surrounded with wildcard characters (*)
Get-ChildItem -Path $rootFolder -Filter "*$($folder.Name)*" -File | Move-Item -Destination $folder.FullName -WhatIf
}
The -WhatIf switch is a safety switch which will only show on screen what files would be moved without actually moving anything. If you find that info is correct, remove the -WhatIf switch from the code and run again.
I'm 99.9% sure there is a better way of doing this, but here's my take:
Get-ChildItem -Path "C:\Path" | Sort-Object -Property "Mode" |
ForEach-Object -Begin {
$files = #{}
} -Process {
if (-not $_.PSIsContainer) {
$files.Add($_.Name,$_.FullName) | Out-Null
}
else {
$folder = $_
$files.GetEnumerator() | ForEach-Object -Process {
if ($_.Key -match $folder.Name) {
Move-Item -Path $_.Value -Destination $folder.FullName -WhatIf
}
}
}
}
Since they are all located in the same directory, you can filter out which one is a file and which one is a folder by sending the files to a hashtable first; this is why we used Sort-Object to organize by filetype listing files at the top. With the files being processed first in our if statement, we know our else block (really not needed) will contain just folders. Finally, we can enumerate our hashtable in order to match file names to folder names. All that's left to do is move the files to their corresponding folder.
Remove the -WhatIf common parameter when you've determined the results displayed are what you're after to perform the actual move.
For /d %%A in (*) do Move "*%%A*" "%%A\" 2>&1>>Nul
Should work - Try it on a test directory first.
Given further information that some target directory names may be substrings of others...
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following setting for the source directory is a name
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
PUSHD "%sourcedir%"
:: remove variables starting #
FOR /F "delims==" %%b In ('set # 2^>Nul') DO SET "%%b="
FOR /f "tokens=1*delims=:" %%b IN ('dir /b /ad ^|findstr /n .') DO SET "#%%b=%%c"&SET /a count=%%b
:: find a directory that is not a substring of another & process it
:reselect
FOR /L %%b IN (1,1,%count%) DO IF DEFINED #%%b (
SET "targetstring=!#%%b!"
FOR /L %%c IN (%%b,1,%count%) DO IF %%b neq %%c IF DEFINED #%%c (FOR %%e IN ("!#%%b!") DO IF /i "!#%%c:%%~e=!" neq "!#%%c!" SET "targetstring=")
IF DEFINED targetstring (
SET "#%%b="
FOR /f "delims=" %%c IN ('dir /b /a-d "*!targetstring!*" 2^>nul') do Move "%%c" "!targetstring!\"
GOTO reselect
)
)
POPD
First, find the directorynames and store them in variable #1..#whatever by submitting them to findstr /n which prefixes each with serial:
Next, repeated scan the array of #n variables, using targetstring as a store of the string being examined. Compare it to each other string in the array and if it's a substring of another, clear targetstring so if targetstring survives, clear the #variable that has this value, process the value and start over.
Repeat until all #variables have been processed - which means they are all deleted from the environment.

Batch rename multiple files in powershell with a prefix

i have more than 200 files in a folder
JOB1_CostReport.xlsx
JOB2_CostReport.xlsx
JOB4_CostReport.xlsx
JOB3_CostReport.xlsx
JOB7_CostReport.xlsx
....
JOB196_CostReport.xlsx
JOB200_CostReport.xlsx
I want to reanme all these files with a suffix like this : JOB1_CostReport_Aug_2020.xlsx
I have tried : Get-ChildItem | rename-item -NewName { $_.Name + "_Aug_2020" }
the result was like this :
JOB1_CostReport.xlsx_Aug_2020
JOB2_CostReport.xlsx_Aug_2020
JOB4_CostReport.xlsx_Aug_2020
JOB3_CostReport.xlsx_Aug_2020
JOB7_CostReport.xlsx_Aug_2020
JOB196_CostReport.xlsx_Aug_2020
JOB200_CostReport.xlsx_Aug_2020
what I want is more like :
JOB1_CostReport_Aug_2020.xlsx
JOB2_CostReport_Aug_2020.xlsx
JOB4_CostReport_Aug_2020.xlsx
JOB3_CostReport_Aug_2020.xlsx
JOB7_CostReport_Aug_2020.xlsx
JOB196_CostReport_Aug_2020.xlsx
JOB200_CostReport_Aug_2020.xlsx
try this:
Get-ChildItem | rename-item -NewName { $_.BaseName + "_Aug_2020" + $_.Extension}
Besides #Brumor's excellent answer in powershell, and as you have tagged this question Cmd, so try this in a batch file:
for %%a in (*) do ren "%%~a" "%%~na_Aug_2020%%~xa"
PS when running in Cmd replace the %% to %.
All the given answers rename the files multiple times(rename the file for 100 times if there are 100 files in the folder and it will add the prefix 100 times).
Use the following command in cmd:
for /f "tokens=*" %a in ('dir /b') do ren "%a" "%%~na_Aug_2020%%~xa"

How to add a new line to the EOF in batch or ps for all files in a folder?

I would like to iterate over all js files in a folder, and add the exact line to all of them. The text should be appended at the end of the file in a new line. I'd like it to be written in a windows supported scripting language like batch or powershell.
My pseudo code would look like:
foreach file in folder
append some text to file in a new line
This can be easily done with a batch-file, using the >> redirection operator, given that every file ends with a line-break:
for %%F in ("%TargetFolder%\*.js") do (
>> "%%~F" echo/This is the new line of text.
)
Or if you want to recurse into sub-directories also:
for /R "%TargetFolder%" %%F in ("*.js") do (
>> "%%~F" echo/This is the new line of text.
)
You can of course first explicitly append a line-break:
for %%F in ("%TargetFolder%\*.js") do (
>> "%%~F" (
echo/
echo/This is the new line of text.
)
)
Or equivalently for the recursive approach, of course.
If you want to append a line-break only in case the file does not already end with such, you could do the following:
for %%F in ("%TargetFolder%\*.js") do (
rem /* Count the number of lines that contain zero or more characters at the end;
rem this is true for every line except for the last when it is not terminated
rem by a line-break, because the `$` is anchored to such: */
for /F %%D in ('findstr ".*$" "%%~F" ^| find /C /V ""') do (
rem // Count the total number of lines in the file:
for /F %%C in ('^< "%%~F" find /C /V ""') do (
>> "%%~F" (
rem // Compare the line counts and conditionally append a line-break:
if %%D lss %%C echo/
echo/This is the new line of text.
)
)
)
)
And again equivalently for the recursive approach.
This is easily done using PowerShell.
Add-Content -Path 'C:\src\t\copyt\*.txt' -Encoding ascii -Value "`nEND"
Or, in a .bat file script.
powershell -NoLogo -NoProfile -Command ^
Add-Content -Path 'C:\src\t\copyt\*.txt' -Encoding ascii -Value "`nEND"
If the files are not large, then to add the line before the last line:
$TempFile = New-TemporaryFile
Get-ChildItem -File -Path 'C:\src\t\copyt' -Filter '*.txt' |
ForEach-Object {
$f = Get-Content -Path $_.FullName
$f[0..($f.Length -2)] + "BOTTOM LINE" + $f[-1] |
Out-File -FilePath $TempFile -Encoding default
Remove-Item -Path $_.FullName
Move-Item -Path $TempFile -Destination $_.FullName
}
Remove-Item -Path $TempFile

Delete whole line in html file recursively with PowerShell

i'm trying to delete the "unwanted" class lines from an HTML file using power shell script
<a class="unwanted" href="http://www.mywebsite.com/rest/of/url1" target="_blank">my_file_name1</a><br>
<a class="mylink" href="http://www.mywebsite.com/rest/of/url2" target="_blank">my_file_name2</a><br>
<a class="unwanted" href="http://www.mywebsite.com/rest/of/url3" target="_blank">my_file_name3</a><br>
Currently i'm replacing strings using this script
$s = "old string"
$r = "new string"
Get-ChildItem "C:\Users\User\Desktop\Folder" -Recurse -Filter *.html | % {
(Get-Content $_.FullName) `
| % { $_ -replace [regex]::Escape($s), $r } `
| Set-Content $_.FullName
}
Since you tagged your question also with cmd and batch-file, I want to contribute a related answer.
cmd.exe/batch scripting does not understand HTML file format, but if your HTML file(s) look(s) like the sample data you provided (the <a> tag and the corresponding </a> tag are in a single line, and there is nothing else (than <br>)), the following command line could work for you -- supposing a HTML file to process is called classes.html and the modified data is to be written to file classes_new.html:
> "classes_new.html" findstr /V /I /L /C:"class=\"unwanted\"" "classes.html"
This only works if the string class="unwanted" occurs only in the <a> tags that need to be removed.
To process multiple files, the following batch script could be used, based on the above command line:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ARGS=%*"
setlocal EnableDelayedExpansion
for %%H in (!ARGS!) do (
endlocal
call :SUB "%%~H"
setlocal
)
endlocal
endlocal
exit /B
:SUB file
if /I not "%~x1"==".html" if /I not "%~x1"==".htm" exit /B 1
findstr /V /I /L /C:"class=\"unwanted\"" "%~f1" | (> "%~f1" find /V "")
exit /B
The actual removal of lines is done in the sub-routine :SUB, unless then file name extension is something other than .html or htm. The main script loops through all the given command line arguments and calls :SUB for every single file. Note that this script does not create new files for the modified HTML contents, it overwrites the given HTML files.
Removing lines is even easier than replacing them. When outputting to Set-Content, simply omit the lines that you want removed. You can do this with Where-Object in place of your Foreach.
Adapting your example:
$s = "unwanted regex"
Get-ChildItem "C:\Users\User\Desktop\Folder" -Recurse -Filter *.html | % {
(Get-Content $_.FullName) `
| where { $_ -notmatch $s } `
| Set-Content $_.FullName
}
If you want literal matching instead of regex, substitute the where clause
where { -not $_.Contains($s) } `
Note this is using the .NET function [String]::Contains(), and not the PowerShell operator -contains, as the latter doesn't work on strings.
Try using multiline strings for your $s and $r. I tested with the HTML examples you posted as well and that worked fine.
$s = #"
old string
"#
$r = #"
new string
"#
Get-ChildItem "C:\Users\User\Desktop\Folder" -Recurse -Filter *.html | % {
(Get-Content $_.FullName) `
| % { $_ -replace $s, $r } `
| Set-Content $_.FullName
}

Batch Script for filtering rows from textfile

first of all: I'm on a Windows 7 machine ;).
I got a folder with several dozens files. Each file contains about 240.000 rows. But only half of that rows are needed.
What I would like to do is: have a script that runs over these files, filters out every row that contains the string "abcd" and have it either saved in a new directory or just saved in the same file.
I would try using Powershell as below:
$currentPath = "the path these files currently in"
$newPath = "the path you want to put the new files"
$files = Get-ChildItem $currentPath
foreach ($item in $files) {
Get-Content $item | Where-Object {$_ -notmatch 'abcd'} |Set-Content $newPath\$item
}
#echo off
setlocal enableextensions
set "_where=c:\some\where\*.txt"
set "_filter=abcd"
rem find files which needs filter
for /f "tokens=*" %%f in ('findstr /m "%_filter%" "%_where%"') do (
rem generate a temporary file with the valid content
findstr /v /c:"%_filter%" "%%~ff" > "%%~ff.tmp"
rem rename original file to .old
ren "%%~ff" *.old > nul
rem rename temporary file as original file
ren "%%~ff.tmp" "%%~nxf" > nul
)
rem if needed, delete *.old files
you might use sed for Windows
sed -i.bak "/abcd/!d" *.txt
Find all abcd containing rows in .txt files, make a backup file .bak and store the the detected lines in the original file.
#echo on
For %%a in (*.txt) do (CALL:FILTER "%%a")
echo/Done.&pause>nul&exit/b
:FILTER
type "%~1"|find "abcd" 1>nul 2>nul
if %errorlevel% EQU 0 find /n "abcd" "%~1">"Found abcd in %~1.txt"
The command Find returns error level = 0 if him find something
If the files are that big, I'd so something like this:
$Folder = 'C:\MyOldFiles'
$NewFolder = 'C:\MyNewFiles'
New-Item -ItemType Directory -Path $NewFolder -Force
foreach ($file in Get-ChildItem $Folder)
{
Get-Content $file -ReadCount 1500 |
foreach { $_ -notmatch 'abcd' } |
Add-Content "$NewFolder\$($file.name)"
}