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:
- Simply loop through all of the parameters and see if we can save them to a variable and then echo them out.
- Figure out how to extract the SubFolderName (This will later be the file name), and echo it per each loop.
- Build the Extract folder and echo per each loop.
- 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.
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 therenames.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
What Are The Advantages Napi Before The Irq Coalesce
Distributing Binary Applications Across Linux Distros
How to Get The UId of The Other End of a Unix Socket Connection
Why How to Cast Sockaddr to Sockaddr_In
Does Socket Io Involve Disk Io
Specifying Non-Standard Baud Rate for Ftdi Virtual Serial Port Under Linux
What's the Difference Between ./Script.Sh and Bash Script.Sh
C Program Shows %Zu After Conversion to Windows
Read a File and Split Each Line into Multiple Variables
How to Set Process Group of a Shell Script
What Does 'Set -O Errtrace' Do in a Shell Script
Less Gets Keyboard Input from Stderr
Bash 'Swallowing' Sub-Shell Children Process When Executing a Single Command
Why Doing I/O in Linux Is Uninterruptible
How to Set My Application's Desktop Icon for Linux: Kde, Gnome etc