Is there a way to rename a directory full of files named with the following convention, without using regex? For instance, I have files named 1.json
, 2.json
, 3.json
, 4.json
and I want them all renamed to their current #{NUM}
to #{NUM - 1}
so the result set would be: 0.json
, 1.json
, 2.json
, 3.json
.
Using the convention:
for i in *.json; do mv -- "$i" ..
Is it possible to do this without regex? Or am I stuck parsing for the file name, converting a string to integer and going from there?
CodePudding user response:
${var%suffix}
will remove a trailing suffix. You can use it to strip off .json
and get just the numbers.
for file in *.json; do
i="${file%.json}"
echo mv -- "$i".json "$((i-1))".json
done
Remove the echo
if it looks good.
Note that this will only handle single digit file names. To handle multi-digit file names we need to have them sorted naturally rather than lexicographically. Lexicographic sorting puts 10
before 9
since the character 1
is less than 9
, meaning 10.json
will get renamed to 9.json
before 9.json
is renamed to 8.json
. Natural sorting, by contrast, will sort 9
before 10
.
Sadly, this makes the whole thing ten times more cryptic. Globs can't be sorted inline so we have to move things around so that we can pipe the list of file names to sort -g
. Then to loop over a stream of file names we have to change from a for
loop to a while read
loop with process substitution.
The basic skeleton structure looks like this:
while read file; do
...
done < <(ls *.json | sort -g)
Then we'll layer on a few improvements:
Use
while IFS= read -r
to make the parsing more robust.Avoid parsing
ls
by switching to aprintf
-based technique to print the file names.Use NUL separators instead of newlines, since newlines are technically legal characters in file names. That means adding
\0
toprintf
,-z
tosort
, and-d $'\0'
toread
to get each of the three to emit and consume NULs.
These steps are good general habits, but I'll admit they're not terribly important for this particular script, and they make the code look like Frankenstein's monster. I'm showing them here for pedagogical purposes. I won't tell if you remove them from your one-off personal use script.
Final, robust solution:
while IFS= read -rd $'\0' file; do
i="${file%.json}"
echo mv -- "$i".json "$((i-1))".json
done < <(printf '%s\0' *.json | sort -zg)
CodePudding user response:
You may use this awk
based solution:
printf '%s\n' [1-9]*.json | sort -n |
awk -F. '{print "mv", $0, ($1-1 FS $2)}' | bash
mv 1.json 0.json
mv 2.json 1.json
mv 3.json 2.json
mv 4.json 3.json
mv 5.json 4.json
Once you're happy with the output you can remove echo
before mv
.
CodePudding user response:
try this code. simpy by -1 from filename.
but if your filename contains zero at first name, lets say 001.json
..n then there is 1.json
, this code will not work. because it will replace the current 1.json
file
declare -i newName=0
for i in `ls | sort -n | grep ".json"`
do
newName=${i%%.*}-1
mv -- "$i" "$newName.json"
done