Batch Renaming Files in Command Line and Xargs

Batch renaming files in command line and Xargs

how do i rename the file so that I can just have one extension.

cd dir/with/messedup/files

for file in *.png.jpg; do
mv "$file" "${file%.png.jpg}.jpg"
done

in the future, using xargs, how do I change the extension of the file simular to second command?

To my knowledge, that can't be done. The best way to do it would be to use a for-loop with parameter substitution much like the one above:

for file in *.png; do
convert "$file" -resize "${file%.png}.jpg"
done

If you have files in subdirectories that you want converted, then you can pipe find to a while read loop:

find . -type f -name '*.png' |
while read file; do
convert "$file" -resize "${file%.png}.jpg"
done

NOTE: It's generally considered a bad idea to use the output of ls in a shell script. While your example might have worked fine, there are lot's of examples where it doesn't. For instance, if your filenames happened to have newlines in them (which unix allows), ls probably won't escape those for you. (That actually depends on your implementation, which is another reason not to use ls in scripts; it's behavior varies greatly from one box to the next.) You'll get more consistent results if you either use find in a while-read loop or file globbing (e.g. *.png) in a for loop.

renaming series of files using xargs

Remember that shell variable substitution happens before your command runs. So when you run:

find . -type f -print0 | \
xargs -I {} -n 1 -0 mv {} "${{}/.txt/.tx}"

The shell tries to expan that ${...} construct before xargs even
runs...and since that contents of that expression aren't a valid shell variable reference, you get an error. A better solution would be to use the rename command:

find . -type f -print0 | \
xargs -I {} -0 rename .txt .tx {}

And since rename can operate on multiple files, you can simplify
that to:

find . -type f -print0 | \
xargs -0 rename .txt .tx

Rename file using xargs -a file

I found my answer at this link:

http://www.commandlinefu.com/commands/view/8368/bulk-rename-files-with-sed-one-liner

It isn't exactly what I wanted to do, but it works:

ls *.log | sed -e 'p;s/.log/.txt/' | xargs -n2 mv

Command Line (or batch file) rename all files in a folder (Windows)

short answer



On Windows, you can use PowerShell, that is installed by default on Windows 7, and can be downloaded and installed on previous versions. With PowerShell you can do the rename as:

ls | foreach-object -process {ren $_ (%{$_ -replace "-straight",""})}

On Unix/Linux, nothing specific needs to be installed, and you can do the rename as:

ls | awk '{print("mv "$1" "$1)}' | cut -f -3,5- -d '-' | sh


examples

Windows Example

Given

PS C:\rename-me> ls

Directory: C:\rename-me

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 10/9/2011 1:35 PM 0 REDHI20806-straight-bottle.png
-a--- 10/9/2011 1:35 PM 0 REDHI20807-straight-bottle.png
-a--- 10/9/2011 1:35 PM 0 REDHI20808-straight-bottle.png
-a--- 10/9/2011 1:35 PM 0 REDHI20809-straight-bottle.png
-a--- 10/9/2011 1:35 PM 0 REDHI20810-straight-bottle.png

Doing It

PS C:\rename-me> ls | foreach-object -process {ren $_ (%{$_ -replace "-straight",""})}

Result

PS C:\rename-me> ls

Directory: C:\rename-me

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 10/9/2011 1:35 PM 0 REDHI20806-bottle.png
-a--- 10/9/2011 1:35 PM 0 REDHI20807-bottle.png
-a--- 10/9/2011 1:35 PM 0 REDHI20808-bottle.png
-a--- 10/9/2011 1:35 PM 0 REDHI20809-bottle.png
-a--- 10/9/2011 1:35 PM 0 REDHI20810-bottle.png


Unix/Linux Example

Given

$ ls -l
total 0
-rw-r--r-- 1 user staff 0 Oct 7 00:54 REDHI20806-straight-bottle.png
-rw-r--r-- 1 user staff 0 Oct 7 00:54 REDHI20807-straight-bottle.png
-rw-r--r-- 1 user staff 0 Oct 7 00:54 REDHI20808-straight-bottle.png
-rw-r--r-- 1 user staff 0 Oct 7 00:54 REDHI20809-straight-bottle.png
-rw-r--r-- 1 user staff 0 Oct 7 00:54 REDHI20810-straight-bottle.png

Doing It

$ ls | awk '{print("mv "$1" "$1)}' | cut -f -3,5- -d '-' | sh

Result

$ ls -l
total 0
-rw-r--r-- 1 user staff 0 Oct 7 00:54 REDHI20806-bottle.png
-rw-r--r-- 1 user staff 0 Oct 7 00:54 REDHI20807-bottle.png
-rw-r--r-- 1 user staff 0 Oct 7 00:54 REDHI20808-bottle.png
-rw-r--r-- 1 user staff 0 Oct 7 00:54 REDHI20809-bottle.png
-rw-r--r-- 1 user staff 0 Oct 7 00:54 REDHI20810-bottle.png

Renaming and moving files while in a loop in a batch script

This is going to be more of a lesson on how to do reasonably good programing in *cough* a bad *cough* the batch programming language.

The first stage is to work from the outside inwards, or top down. It only took a few minutes to build this framework. The sub goals/steps are:

  1. Simply loop through all of the parameters and see if we can save them to a variable and then echo them out.
  2. Figure out how to extract the SubFolderName (This will later be the file name), and echo it per each loop.
  3. Build the Extract folder and echo per each loop.
  4. Realize you forgot you were going to need the folder path of the calling batch file, add it as first parameter, and extract it before entering the :ltpLoop.

The %1 gets the first parameter, while SHIFT will shift all parameters so that %1=%2, %2=%3, %3=%4, %4=%5, etc... This effectively removes the first parameter and reduces the total number of parameters by 1. The IF statement exits the script when SHIFT has removed all parameters and %1 no longer has a value.

Also, a lot of people will follow the ECHO command with a period (ECHO.Text to echo), but I had one bad case where period printed a blank line instead of the text, but semicolon ; was fine - so I no do period, period!

@ECHO OFF
GOTO :Start

:LoopThroughParameters
SET CmdPath=%~1
SHIFT
ECHO;[[[%CmdPath%]]]
:ltpLoop
IF [%1] EQU [] GOTO :EOF
SET Folder=%~1
SET SubFolderName=%~nx1
SET ExtractFolder=%~1\Extract

ECHO;
ECHO;[%Folder%]
ECHO;[%SubFolderName%]
ECHO;[%ExtractFolder%]
SHIFT
GOTO :ltpLoop

:Start
CALL :LoopThroughParameters "%~dp0" %*
PAUSE

In stage 2 we start by cleaning up the code by removing the unneeded echos.

:LoopThroughParameters
SET CmdPath=%~1
SHIFT

:ltpLoop
IF [%1] EQU [] GOTO :EOF
SET Folder=%~1
SET SubFolderName=%~nx1
SET ExtractFolder=%~1\Extract
<<New Code Will Go Here>>
SHIFT
GOTO :ltpLoop

Start experimenting in the <<New Code Will Go Here>> area.

    ECHO;FOR %%C IN ("%Folder%\*.zip" "%Folder%\*.rar") DO (

The code is tested by creating 5 folders, with one zip file in each folder, and dragging the folders on to the batch file and seeing if we like the commands it built.

FOR %C IN ("D:\Temp\StackOverflow\71345433\volume5\*.zip" "D:\Temp\StackOverflow\71345433\volume5\*.rar") DO (
FOR %C IN ("D:\Temp\StackOverflow\71345433\volume1\*.zip" "D:\Temp\StackOverflow\71345433\volume1\*.rar") DO (
FOR %C IN ("D:\Temp\StackOverflow\71345433\volume2\*.zip" "D:\Temp\StackOverflow\71345433\volume2\*.rar") DO (
FOR %C IN ("D:\Temp\StackOverflow\71345433\volume3\*.zip" "D:\Temp\StackOverflow\71345433\volume3\*.rar") DO (
FOR %C IN ("D:\Temp\StackOverflow\71345433\volume4\*.zip" "D:\Temp\StackOverflow\71345433\volume4\*.rar") DO (

Then we try to build the extraction commands:

    FOR %%C IN ("%Folder%\*.zip" "%Folder%\*.rar") DO (
ECHO;"%ProgramFiles%\7-Zip\7z.exe" e -o"%ExtractFolder%" "%%~C"
)

Check if results look correct:

"C:\Program Files\7-Zip\7z.exe" e -o"D:\Temp\StackOverflow\71345433\volume5\Extract" "D:\Temp\StackOverflow\71345433\volume5\Last Zip file.zip"
"C:\Program Files\7-Zip\7z.exe" e -o"D:\Temp\StackOverflow\71345433\volume1\Extract" "D:\Temp\StackOverflow\71345433\volume1\SomeZipFile.zip"
"C:\Program Files\7-Zip\7z.exe" e -o"D:\Temp\StackOverflow\71345433\volume2\Extract" "D:\Temp\StackOverflow\71345433\volume2\JustAnotherZip.zip"
"C:\Program Files\7-Zip\7z.exe" e -o"D:\Temp\StackOverflow\71345433\volume3\Extract" "D:\Temp\StackOverflow\71345433\volume3\YetAnotherZip.zip"
"C:\Program Files\7-Zip\7z.exe" e -o"D:\Temp\StackOverflow\71345433\volume4\Extract" "D:\Temp\StackOverflow\71345433\volume4\How Many Zips Was This.zip"

In stage 3 we try it for real - remove the echo:

"%ProgramFiles%\7-Zip\7z.exe" e -o"%ExtractFolder%" "%%~C"

Check if we like the results (You can see I'm using some old latitude-e5440 PDFs I happen to find in a forgotten folder someplace):

D:\Temp\StackOverflow\71345433>dir /s /b
D:\Temp\StackOverflow\71345433\DragDropAndExtract.CMD
D:\Temp\StackOverflow\71345433\volume1
D:\Temp\StackOverflow\71345433\volume2
D:\Temp\StackOverflow\71345433\volume3
D:\Temp\StackOverflow\71345433\volume4
D:\Temp\StackOverflow\71345433\volume5
D:\Temp\StackOverflow\71345433\volume1\Extract
D:\Temp\StackOverflow\71345433\volume1\SomeZipFile.zip
D:\Temp\StackOverflow\71345433\volume1\Extract\lat_e_reimage_guide_en-us.pdf
D:\Temp\StackOverflow\71345433\volume2\Extract
D:\Temp\StackOverflow\71345433\volume2\JustAnotherZip.zip
D:\Temp\StackOverflow\71345433\volume2\Extract\latitude-e5440-laptop_owners-manual_en-us.pdf
D:\Temp\StackOverflow\71345433\volume3\Extract
D:\Temp\StackOverflow\71345433\volume3\YetAnotherZip.zip
D:\Temp\StackOverflow\71345433\volume3\Extract\latitude-e5440-laptop_user's guide_en-us.pdf
D:\Temp\StackOverflow\71345433\volume4\Extract
D:\Temp\StackOverflow\71345433\volume4\How Many Zips Was This.zip
D:\Temp\StackOverflow\71345433\volume4\Extract\latitude-e5440-laptop_users-guide_en-us.pdf
D:\Temp\StackOverflow\71345433\volume5\Extract
D:\Temp\StackOverflow\71345433\volume5\Last Zip file.zip
D:\Temp\StackOverflow\71345433\volume5\Extract\latitude-e5440-laptop_white papers_en-us.pdf

For stage 4 we echo both the extract command and xcopy command to see what they look like:

        ECHO;"%ProgramFiles%\7-Zip\7z.exe" e -o"%ExtractFolder%" "%%~C"
ECHO; XCOPY /V /C /Y "%ExtractFolder%\*.*" "%CmdPath%\%SubFolderName%.*"

Just a reminder, every test is done by dragging the 5 folders onto the batch file:

"C:\Program Files\7-Zip\7z.exe" e -o"D:\Temp\StackOverflow\71345433\volume5\Extract" "D:\Temp\StackOverflow\71345433\volume5\Last Zip file.zip"
XCOPY /V /C /Y "D:\Temp\StackOverflow\71345433\volume5\Extract\*.*" "D:\Temp\StackOverflow\71345433\\volume5.*"
"C:\Program Files\7-Zip\7z.exe" e -o"D:\Temp\StackOverflow\71345433\volume1\Extract" "D:\Temp\StackOverflow\71345433\volume1\SomeZipFile.zip"
XCOPY /V /C /Y "D:\Temp\StackOverflow\71345433\volume1\Extract\*.*" "D:\Temp\StackOverflow\71345433\\volume1.*"
"C:\Program Files\7-Zip\7z.exe" e -o"D:\Temp\StackOverflow\71345433\volume2\Extract" "D:\Temp\StackOverflow\71345433\volume2\JustAnotherZip.zip"
XCOPY /V /C /Y "D:\Temp\StackOverflow\71345433\volume2\Extract\*.*" "D:\Temp\StackOverflow\71345433\\volume2.*"
"C:\Program Files\7-Zip\7z.exe" e -o"D:\Temp\StackOverflow\71345433\volume3\Extract" "D:\Temp\StackOverflow\71345433\volume3\YetAnotherZip.zip"
XCOPY /V /C /Y "D:\Temp\StackOverflow\71345433\volume3\Extract\*.*" "D:\Temp\StackOverflow\71345433\\volume3.*"
"C:\Program Files\7-Zip\7z.exe" e -o"D:\Temp\StackOverflow\71345433\volume4\Extract" "D:\Temp\StackOverflow\71345433\volume4\How Many Zips Was This.zip"
XCOPY /V /C /Y "D:\Temp\StackOverflow\71345433\volume4\Extract\*.*" "D:\Temp\StackOverflow\71345433\\volume4.*"

Stage 5, try it live:

        "%ProgramFiles%\7-Zip\7z.exe" e -o"%ExtractFolder%" "%%~C"
XCOPY /V /C /Y "%ExtractFolder%\*.*" "%CmdPath%\%SubFolderName%.*"

What did we get?:

D:\Temp\StackOverflow\71345433>dir /s/b
D:\Temp\StackOverflow\71345433\volume1
D:\Temp\StackOverflow\71345433\volume1.pdf
D:\Temp\StackOverflow\71345433\volume2
D:\Temp\StackOverflow\71345433\volume2.pdf
D:\Temp\StackOverflow\71345433\volume3
D:\Temp\StackOverflow\71345433\volume3.pdf
D:\Temp\StackOverflow\71345433\volume4
D:\Temp\StackOverflow\71345433\volume4.pdf
D:\Temp\StackOverflow\71345433\volume5
D:\Temp\StackOverflow\71345433\volume5.pdf

Stage 6, what will remove directory look like? (Decided to hide the other commands with REM)

        REM "%ProgramFiles%\7-Zip\7z.exe" e -o"%ExtractFolder%" "%%~C"
REM XCOPY /V /C /Y "%ExtractFolder%\*.*" "%CmdPath%\%SubFolderName%.*"
ECHO;RD /Q /S "%Folder%"

And we have:

RD /Q /S "D:\Temp\StackOverflow\71345433\volume5"
RD /Q /S "D:\Temp\StackOverflow\71345433\volume1"
RD /Q /S "D:\Temp\StackOverflow\71345433\volume2"
RD /Q /S "D:\Temp\StackOverflow\71345433\volume3"
RD /Q /S "D:\Temp\StackOverflow\71345433\volume4"

Stage 7 is the final code and tests:

@ECHO OFF
GOTO :Start

:LoopThroughParameters
SET CmdPath=%~1
SHIFT

:ltpLoop
IF [%1] EQU [] GOTO :EOF
SET Folder=%~1
SET SubFolderName=%~nx1
SET ExtractFolder=%~1\Extract

FOR %%C IN ("%Folder%\*.zip" "%Folder%\*.rar") DO (
"%ProgramFiles%\7-Zip\7z.exe" e -o"%ExtractFolder%" "%%~C"
XCOPY /V /C /Y "%ExtractFolder%\*.*" "%CmdPath%\%SubFolderName%.*"
RD /Q /S "%Folder%"
)

SHIFT
GOTO :ltpLoop

:Start
CALL :LoopThroughParameters "%~dp0" %*
PAUSE

All folders were deleted when done.

Now, let's do something experimental. I've never seen this fail, but I haven't used it that often. Let's give it a try:

@ECHO OFF
GOTO :Start

:LoopThroughParameters
SET CmdPath=%~1
SHIFT

:ltpLoop
IF [%1] EQU [] GOTO :EOF
SET Folder=%~1
SET SubFolderName=%~nx1
SET ExtractFolder=%~1\Extract

FOR %%C IN ("%Folder%\*.zip" "%Folder%\*.rar") DO (
(
"%ProgramFiles%\7-Zip\7z.exe" e -o"%ExtractFolder%" "%%~C"
) && (
XCOPY /V /C /Y "%ExtractFolder%\*.*" "%CmdPath%\%SubFolderName%.*"
) && (
RD /Q /S "%Folder%"
) || (
PowerShell Write-Host -ForegroundColor red "Error:"
PAUSE
)
)

SHIFT
GOTO :ltpLoop

:Start
CALL :LoopThroughParameters "%~dp0" %*

If any of the commands separated by && fail, then execution jumps to the command prefixed by ||. But if all of the commands separated by && succeed without throwing an error code, then the command prefixed by || is skipped. In theory, this will prevent the folder from being deleted, and pause the code, if there is problem.

So, we re-created the folders, and then used HxD to the damage zip file in volume4 folder.
HxD making a PDF Bad

It worked perfectly! Folder volume4 was not deleted. Tried the test again, this time damaging the PDF in folder volume2, worked perfectly!

As you can tell, I can do things in Batch that many can't do in PowerShell, and yes @Olaf, that's not necessarily something to be proud of! ;)

How do I recursively rename files with cmd

This is easy enough with PowerShell. When you are satisfied that the correct files are renamed correctly, remove the -WhatIf from the Rename-Item command.

Get-ChildItem -Recurse -File -Filter 'configfile.xml' |
ForEach-Object { Rename-Item -Path $_.FullName -NewName 'config.xml' -WhatIf }

If you must run from a cmd.exe prompt or .bat file script:

powershell -NoLogo -NoProfile -Command ^
"Get-ChildItem -Recurse -File -Filter 'configfile.xml' |" ^
"ForEach-Object { Rename-Item -Path $_.FullName -NewName 'config.xml' -WhatIf }"

Batch rename file extensions, including subdirectories

@echo off
for /f "tokens=* delims= " %%i in ('dir /b/s/A-d') DO (
if "%%~xi" == "" rename "%%~fi" "%%~ni.bla"
)

Thanks @Wadih M. Find and rename files with no extension?

How to rename all files to lowercase (solved) and simultaneously spaces to underscores

You can use:

find . -depth -print0 | 
xargs -0 perl-rename -n 's~([^/]+)$~\L$1~;s~(?:.*/|\G)\K(\S+)\s+(?![^/]*/)~$1_~g'

RegEx Demo

Rename multiple files in a folder, add a line counts as prefix (Powershell)

What you are doing is almost fine, the error comes from trying to concatenate an int with a string, PowerShell attempts type conversion of all elements to the type of the leftmost object in the operation:

The operation that PowerShell performs is determined by the Microsoft .NET type of the leftmost object in the operation. PowerShell tries to convert all the objects in the operation to the .NET type of the first object. If it succeeds in converting the objects, it performs the operation appropriate to the .NET type of the first object. If it fails to convert any of the objects, the operation fails.

Since the leftmost object in this case (the .Length property) is of the type int PowerShell attempts to convert the rest to int and it fails, for example:

PS /> 1 + 'A'
InvalidArgument: Cannot convert value "A" to type "System.Int32". Error: "Input string was not in a correct format."

This would be easily fixed by type casting the returned value to sring:

-NewName { [string](Get-Content $_).Length + "_" + $_.BaseName + $_.Extension }

Or for example using string formatting or the -f format operator:

-NewName { '{0}_{1}{2}' -f (Get-Content $_).Length, $_.BaseName, $_.Extension }

As for "the bonus", with string formatting see How do I control the number of integral digits?

In this case you can use {0:0000}, as an example:

(0..1000).ForEach({'{0:0000}' -f $_})

On the other hand, if you have many lengthy files, [System.IO.File]::ReadAllLines(...) is likely to be faster than Get-Content:

-NewName { '{0:0000}_{1}' -f [System.IO.File]::ReadAllLines($_).Length, $_.Name }
# OR
$io = [System.IO.File]
-NewName { '{0:0000}_{1}' -f $io::ReadAllLines($_).Length, $_.Name }

Rename files reading old file name and new file name from a txt file (bash)

xargs -a renames.txt -n 2 sh -c 'echo mv -- "$1.fas" "$2.fas"' _
  • xargs -a renames.txt: process content of the renames.txt as arguments to a command.
  • -n 2: pick 2 arguments at a time.
  • sh -c: command is to run an inline shell
  • The inline shell 'echo mv -- "$1.fas" "$2.fas"': Performs the actual rename using arguments 1 and 2 provided by xargs.
# remove echo when output matches the intent
echo mv -- "$1.fas" "$2.fas"

Method using a shell only to read renames.txt and execute the renames:

while read -r a b; do
# Remove echo if satisfied by the output
echo mv -- "$a.fas" "$b.fas"
done <renames.txt

Alternate method with awk to transform the renames.txt file into a shell script with the rename commands:

awk '{print "mv -- "$1".fas "$2".fas"}' renames.txt

Once satisfied by the output of awk above; save to a shell script file, or pipe directly to sh.



Related Topics



Leave a reply



Submit