2

These are my sample files

user@linux:~$ ls -l | cut -d ' ' -f 10-
ch 10 - file.txt
ch 2 - file.txt
ch 3 - file.txt
ch 4a - file.txt
ch 5 - file.txt
user@linux:~$ 

I would like to add 0 to any single digit (including 4a) so the final output would be like this.

user@linux:~$ ls -l | cut -d ' ' -f 10-
ch 10 - file.txt
ch 02 - file.txt
ch 03 - file.txt
ch 04a - file.txt
ch 05 - file.txt
user@linux:~$ 

Is this possible using built-in tools in Linux?

asked Dec 15, 2019 at 3:52
1

4 Answers 4

1

The pattern

'ch '[1-9][!0-9]*'- file.txt'

would match all filenames that needs changing (out of the ones that you show), i.e. any filename that starts with ch , followed by a digit between 1 and 9, followed by something that is not a digit. After that, we allow for any characters whatsoever, and the names must end with - file.txt.

We can loop over these files with

for name in 'ch '[1-9][!0-9]*'- file.txt'; do
 ...
done

The objective is now to insert a 0 after the ch bit. This can be done by stripping the ch substring off, and replacing it with ch 0:

for name in 'ch '[1-9][!0-9]*'- file.txt'; do
 newname='ch 0'${name#ch }
done

The ${name#ch } parameter substitution would expand to 2 - file.txt if $name contained ch 2 - file.txt (it would remove the prefix ch ).

After this, you could just rename the file:

for name in 'ch '[1-9][!0-9]*'- file.txt'; do
 newname='ch 0'${name#ch }
 printf 'would rename "%s" into "%s"\n' "$name" "$newname"
 # mv -i "$name" "$newname"
done

Remove the # on the line with the commented out mv command after running the loop once to see that it does the correct thing.

The loop above, given the filenames that you show, would output

would rename "ch 2 - file.txt" into "ch 02 - file.txt"
would rename "ch 3 - file.txt" into "ch 03 - file.txt"
would rename "ch 4a - file.txt" into "ch 04a - file.txt"
would rename "ch 5 - file.txt" into "ch 05 - file.txt"
answered Dec 15, 2019 at 9:17
1

With Lary Wall's rename/prename (rename in Debian/Ubuntu, prename in RedHat/Fedora):

rename -n 's/^ch (\d) /ch 01ドル /' *

-n is for dry runs, remove (or replace with `-v') for actual execution.

answered Dec 15, 2019 at 9:46
0

With zsh:

autoload zmv # best in .zshrc
zmv -n '*[0-9]*' '${f//(#m)<->/${(l:2::0:)MATCH}}'

(remove -n (dry-run) if happy).

Would left-pad all numbers to width 2.

Beware it also truncates numbers to width 2 (would change 1234-2.txt into 34-02.txt).

Not sure what you mean by builtin, especially in relation to Linux which is just a kernel. autoload is a zsh built-in, but note that the zmv autoloadable function invokes the mv utility which is not a builtin by default (but can be made so with zmodload zsh/files).

answered Dec 15, 2019 at 9:07
0

This is what you are looking for.

What is need to be done basically are as follows:

1, check if the digit is single or double-digit. If it is single digit and the value less than or equal to 9 then, rename the file. Which should be as simple as doing:

(( someDigit <= 9 )) && [[ ${#someDigit'slength} -lt 2 ]]

2, since there would be some files with letters so, we can store them as:

digit=$( echo $file | cut -d '-' -f1 | grep ch | awk '{print 2ドル}' );

3, then filter the digit so that we can compare it for first option. Add more filters which you may feel would be necessary in tr -d option as follows:

digitOnly=$( echo $digit | tr -d [a-Z] ); 

4, then run a loop in your directory where you intend to rename the files. Implementing all of this would look as follows:

for file in *file.txt; do
 digit=$( echo $file | cut -d '-' -f1 | grep ch | awk '{print 2ドル}' );
 digitOnly=$( echo $digit | tr -d [a-Z] );
 if (( digitOnly <= 9 )) && [[ ${#digitOnly} -lt 2 ]]; then
 # mv "${file}" "ch 0${digit} - file.txt"
 echo "'${file}' is renamed to 'ch 0${digit} - file.txt'";
 fi
done

Remove the # from mv, after you are satisfied before real execution. With your example:

touch 'ch 10 - file.txt' 'ch 2 - file.txt' 'ch 3 - file.txt' 'ch 4a - file.txt' 'ch 5 - file.txt'

Then, executing the script or copying pasting the above script in bash will give you the following output:

'ch 2 - file.txt' is renamed to 'ch 02 - file.txt'
'ch 3 - file.txt' is renamed to 'ch 03 - file.txt'
'ch 4a - file.txt' is renamed to 'ch 04a - file.txt'
'ch 5 - file.txt' is renamed to 'ch 05 - file.txt'

Obviously, you can even make it more generic, by including it in a function then take input such as file pattern search and so on, but your question does not demand that. So, I believe, the current answer would handle the situation stated in the question quite well.

answered Dec 15, 2019 at 8:35

You must log in to answer this question.