Rename all files in a directory with a Windows batch script - windows

How would I write a batch or cmd file that will rename all files in a directory? I am using Windows.
Change this:
750_MOT_Forgiving_120x90.jpg
751_MOT_Persecution_1_120x90.jpg
752_MOT_Persecution_2_120x90.jpg
753_MOT_Hatred_120x90.jpg
754_MOT_Suffering_120x90.jpg
755_MOT_Freedom_of_Religion_120x90.jpg
756_MOT_Layla_Testimony_1_120x90.jpg
757_MOT_Layla_Testimony_2_120x90.jpg
To this:
750_MOT_Forgiving_67x100.jpg
751_MOT_Persecution_1_67x100.jpg
752_MOT_Persecution_2_67x100.jpg
753_MOT_Hatred_67x100.jpg
754_MOT_Suffering_67x100.jpg
755_MOT_Freedom_of_Religion_67x100.jpg
756_MOT_Layla_Testimony_1_67x100.jpg
757_MOT_Layla_Testimony_2_67x100.jpg

A FOR statement to loop through the names (type FOR /? for help), and string search and replace (type SET /? for help).
#echo off
setlocal enableDelayedExpansion
for %%F in (*120x90.jpg) do (
set "name=%%F"
ren "!name!" "!name:120x90=67x100!"
)
UPDATE - 2012-11-07
I've investigated how the RENAME command deals with wildcards: How does the Windows RENAME command interpret wildcards?
It turns out that this particular problem can be very easily solved using the RENAME command without any need for a batch script.
ren *_120x90.jpg *_67x100.*
The number of characters after the _ does not matter. The rename would still work properly if 120x90 became x or xxxxxxxxxx. The important aspect of this problem is that the entire text between the last _ and the . is replaced.

As of Windows 7 you can do this in one line of PowerShell.
powershell -C "gci | % {rni $_.Name ($_.Name -replace '120x90', '67x100')}"
Explanation
powershell -C "..." launches a PowerShell session to run the quoted command. It returns to the outer shell when the command completes. -C is short for -Command.
gci returns all the files in the current directory. It is an alias for Get-ChildItem.
| % {...} makes a pipeline to process each file. % is an alias for Foreach-Object.
$_.Name is the name of the current file in the pipeline.
($_.Name -replace '120x90', '67x100') uses the -replace operator to create the new file name. Each occurrence of the first substring is replaced with the second substring.
rni changes the name of each file. The first parameter (called -Path) identifies the file. The second parameter (called -NewName) specifies the new name. rni is an alias for Rename-Item.
Example
$ dir
Volume in drive C has no label.
Volume Serial Number is A817-E7CA
Directory of C:\fakedir\test
11/09/2013 16:57 <DIR> .
11/09/2013 16:57 <DIR> ..
11/09/2013 16:56 0 750_MOT_Forgiving_120x90.jpg
11/09/2013 16:57 0 751_MOT_Persecution_1_120x90.jpg
11/09/2013 16:57 0 752_MOT_Persecution_2_120x90.jpg
3 File(s) 0 bytes
2 Dir(s) 243,816,271,872 bytes free
$ powershell -C "gci | % {rni $_.Name ($_.Name -replace '120x90', '67x100')}"
$ dir
Volume in drive C has no label.
Volume Serial Number is A817-E7CA
Directory of C:\fakedir\test
11/09/2013 16:57 <DIR> .
11/09/2013 16:57 <DIR> ..
11/09/2013 16:56 0 750_MOT_Forgiving_67x100.jpg
11/09/2013 16:57 0 751_MOT_Persecution_1_67x100.jpg
11/09/2013 16:57 0 752_MOT_Persecution_2_67x100.jpg
3 File(s) 0 bytes
2 Dir(s) 243,816,271,872 bytes free

Related

Command for hidden folders for git in windows

What are the commands for showing the hidden folders in Git repository in windows?
For example - command in mac is ls -la or ls -a.
I am new to git.
The simplest way : start a terminal using git-bash, or from WSL (Windows Subsystem for Linux).
You will have a bash shell with access to the standard linux utilies, and ls -la should work from such terminals.
If you started a Powershell terminal, try ls -Hidden.
ls is actually an alias to the powershell command : Get-ChildItem.
The Powershell team mapped a number of usual linux command names to Powershell built-ins (e.g : cd -> Set-Location, uniq -> Get-Unique, pushd -> Push-Location, ... ), but didn't map the options, so the options expected by ls in a Powershell terminal aren't -a ... but rather the options to Get-ChildItem.
One way to figure out what's expected from a "linux" command name you know is to type : get-help <command name> you will see the actual powershell command name, and the options it expects, for example :
$ get-help ls
NAME
Get-ChildItem
SUMMARY
Gets the items and child items in one or more specified locations.
SYNTAX
Get-ChildItem [[-Filter] <System.String>] [-Attributes {Archive | Compressed | Device | Directory | Encrypted |
Hidden | IntegrityStream | Normal | NoScrubData | NotContentIndexed | Offline | ReadOnly | ReparsePoint |
SparseFile | System | Temporary}] [-Depth <System.UInt32>] [-Directory] [-Exclude <System.String[]>] [-File]
[-Force] [-Hidden] [-Include <System.String[]>] -LiteralPath <System.String[]> [-Name] [-ReadOnly] [-Recurse]
[-System] [-UseTransaction] [<CommonParameters>]
Get-ChildItem [[-Path] <System.String[]>] [[-Filter] <System.String>] [-Attributes {Archive | Compressed | Device
| Directory | Encrypted | Hidden | IntegrityStream | Normal | NoScrubData | NotContentIndexed | Offline | ReadOnly
| ReparsePoint | SparseFile | System | Temporary}] [-Depth <System.UInt32>] [-Directory] [-Exclude
<System.String[]>] [-File] [-Force] [-Hidden] [-Include <System.String[]>] [-Name] [-ReadOnly] [-Recurse]
[-System] [-UseTransaction] [<CommonParameters>]
DESCRIPTION
The `Get-ChildItem` cmdlet gets the items in one or more specified locations. [...]
If the OP is asking to simply see the hidden .git folder in a regular Windows Command terminal (cmd.exe), then the easiest is to use the dir command with the /a attribute. This is the simplest native equivalent to ls -a.
C:\Users\--redacted-->dir /a
Volume in drive C has no label.
Volume Serial Number is --redacted--
Directory of C:\Users\--redacted--
2022-10-29 10:31 PM <DIR> .
2022-10-29 10:31 PM <DIR> ..
2022-10-29 10:31 PM <DIR> .git
2022-10-29 10:31 PM 489 .gitignore
...
If you do not use the /a, you don't see the .git folder:
C:\Users\--redacted-->dir
Volume in drive C has no label.
Volume Serial Number is --redacted--
Directory of C:\Users\--redacted--
2022-10-29 10:31 PM <DIR> .
2022-10-29 10:31 PM <DIR> ..
2022-10-29 10:31 PM 489 .gitignore
...
This is because the .git folder has the Hidden Windows file attribute set, as can be seen with the attrib command:
C:\Users\--redacted-->attrib .git
H C:\Users\--redacted--\.git
Enter dir /? for all the flags that can be used with dir.

How to avoid an error when listing nonexistent files?

I'm grouping files by dates in the filenames and processing them by groups.
for m in {01..12}; do
for d in {01..31}; do
f=`ls ./mydir/2018.${m}.${d}T*.jpg`
# process files
done
done
However, the code raises error if no files exist for some dates, e.g.,
ls: cannot access '2018.01.20T*.jpg': No such file or directory
How can I skip missing dates?
Enable nullglob so non-matching wildcards expand to nothing. Then you can skip parsing ls altogether and simply iterate over the matching files.
shopt -s nullglob
for m in {01..12}; do
for d in {01..31}; do
for f in ./mydir/2018.${m}.${d}T*.jpg; do
# process file
done
done
done
If you want all the file names at once, store them in an array. Arrays are better than a plain strings because they can handle file names with spaces and other special characters.
shopt -s nullglob
for m in {01..12}; do
for d in {01..31}; do
files=(./mydir/2018.${m}.${d}T*.jpg)
# process files
echo "processing ${files[#]}..."
done
done
What's the cleanest way to localise the shopt so as to restore nullglob to its original (unknown) value after this block?
Use a subshell: surround the block with parentheses. A subshell creates a child process which ensures changes don't leak into the parent.
(
shopt -s nullglob
...
)
It's polite to do this whenever you're changing shell options, and it's an elegant alternative to pushd+popd. Note that any variable assignments will be local to the subshell, so be careful there.
Here is another way, using find:
Assume the following dir:
$ ls -l mydir/
total 0
-rw-r--r-- 1 0 Jan 23 16:46 2018.01.20Thellowet.jpg
-rw-r--r-- 1 0 Jan 23 16:47 2018.04.24Thellowet.jpg
-rw-r--r-- 1 0 Jan 23 16:46 some_random_crap
-rw-r--r-- 1 0 Jan 23 16:46 wet
-rw-r--r-- 1 0 Jan 23 16:46 when
-rw-r--r-- 1 0 Jan 23 16:46 who
-rw-r--r-- 1 0 Jan 23 16:46 wtf
Using find:
find ./mydir/ -type f -regextype sed -regex ".*2018\.[0-9]\{,2\}\.[0-9]\{,2\}T.*\.jpg.*" -exec echo "---{}" \;
Gives (minor processing of data by appending --- to the file name):
---./mydir/2018.04.24Thellowet.jpg
---./mydir/2018.01.20Thellowet.jpg
NOTE: This will also return files that have 2018.00.xy or 2018.xy.00 where x and y can be any number between 0 and 9
Regex explained:
.* : any pattern
[0-9]{,2}: a 2 digit number
The \ are used to escape special characters.

List only directories, including directories with spaces in their names? [duplicate]

This question already has answers here:
Listing only directories using ls in Bash? [closed]
(29 answers)
Closed 4 years ago.
I would like to list all directories in a directory. Some of them have spaces in their names. There are also files in the target directory, which I would like to ignore.
Here is the output of ls -lah data/:
drwxr-xr-x 5 me staff 160B 24 Sep 11:30 Wrecsam - Wrexham
-rw-r--r-- 1 me staff 77M 24 Sep 11:31 Wrexham.csv
drwxr-xr-x 5 me staff 160B 24 Sep 11:32 Wychavon
-rw-r--r-- 1 me staff 84M 24 Sep 11:33 Wychavon.csv
I would like to iterate only over the "Wrecsam - Wrexham" and "Wychavon" directories.
This is what I've tried.
for d in "$(find data -maxdepth 1 -type d -print | sort -r)"; do
echo $d
done
But this gives me output like this:
Wychavon
Wrecsam
-
Wrexham
I want output like this:
Wychavon
Wrecsam - Wrexham
What can I do?
Your for loop is not doing the right thing because of word splitting. You can use a glob instead of having to invoke an external command in a subshell:
shopt -s nullglob # make glob expand to nothing if there are no matches
for dir in data/*/; do
echo dir="$dir"
done
Related:
Looping over directories in Bash
Why you shouldn't parse the output of ls(1)

Bash Bug? Can't use negate extglob !(*/) to filter out directories?

If the glob */ only matches directories, then logically the extglob !(*/) should match non-directories; but this doesn't work. Is this a bug or am I missing something? Does this work on any shell?
Test 1 to prove that */ works
$ cd /tmp; ls -ld */
drwxr-xr-x 2 seand users 4096 Jan 1 15:59 test1//
drwxr-xr-x 2 seand users 4096 Jan 1 15:59 test2//
drwxr-xr-x 2 seand users 4096 Jan 1 15:59 test3//
Test 2 to show potential bug with !(*/)
$ cd /tmp; shopt -s extglob; ls -ld !(*/)
/bin/ls: cannot access !(*/): No such file or directory
In Bash, !() (like *, ?, *(), and #()) only applies to one path component. Thus, !(anything containing a / slash) doesn't work.
If you switch to zsh, you can use *(^/) to match all non-directories, or *(.) to match all plain files.
The answer to the specific question has already been given; and I am not sure if you really wanted another solution or if you were just interested to analyze the behavior, but one way to list all non-directories in the current folder is to use find:
find . ! -type d -maxdepth 1

Show full path when using options

I often use this list command in Unix (AIX / KSH):
ls -Artl
It displays the files as this:
-rw-r--r-- 1 myuser mygroup 0 Apr 2 11:59 test1.txt
-rw-r--r-- 1 myuser mygroup 0 Apr 2 11:59 test2.txt
I would like to modify the command such a way that the full path of the file is displayed. For example:
-rw-r--r-- 1 myuser mygroup 0 Apr 2 11:59 /usr/test1.txt
-rw-r--r-- 1 myuser mygroup 0 Apr 2 11:59 /usr/test2.txt
Any ideas?
I found several resolution methods using pwd or find but - as far as I see - this does not work work if I want to keep the ls options.
What about this trick...
ls -lrt -d -1 $PWD/{*,.*}
OR
ls -lrt -d -1 $PWD/*
I think this has problems with empty directories but if another poster has a tweak I'll update my answer. Also, you may already know this but this is probably be a good candidate for an alias given it's lengthiness.
[update] added some tweaks based on comments, thanks guys.
[update] as pointed out by the comments you may need to tweek the matcher expressions depending on the shell (bash vs zsh). I've re-added my older command for reference.
Try this, works for me: ls -d /a/b/c/*
Use this command:
ls -ltr /mig/mthome/09/log/*
instead of:
ls -ltr /mig/mthome/09/log
to get the full path in the listing.
I use this command:
ls -1 | xargs readlink -f
optimized from spacedrop answer ...
ls $(pwd)/*
and you can use ls options
ls -alrt $(pwd)/*
simply use find tool.
find absolute_path
displays full paths on my Linux machine, while
find relative_path
will not.
I wrote a shell script called fullpath that contains this code, use it everyday:
#!/bin/sh
for i in $* ; do
echo $(pwd)/$i
done
Put it somewhere in your PATH, and make it executable(chmod 755 fullpath) then just use
fullpath file_or_directory
You can combine the find command and the ls command. Use the path (.) and selector (*) to narrow down the files you're after. Surround the find command in back quotes. The argument to -name is doublequote star doublequote in case you can't read it.
ls -lart `find . -type f -name "*" `

Resources