2

I have a bunch of SVG files in a dir.

0.svg 
1.svg 
2.svg ...
42Group.svg 
500px.svg
file1.svg 
file2.svg ...

I'd like to add a letter A if a file name starts with a number.

For example, I'd like to change 0.svg to A0Solid.svelte.

Currently I have the following that converts file names:

rename -v 's/./\U$&/;s/-(.)/\U$1/g;s/\.svg$/Solid.svelte/' -- *.svg > /dev/null 2>&1

But this converts 0.svg to 0Solid.svelte. I'd like to change it to A0Solid.svelte.

How can I do it with Bash/Shell?

[Updates]: I added 42Group.svg 500px.svg to the file names.

3
  • The text says to append the letter A, but your code and examples imply that you'd like to also modify the rest of the name by adding Solid before the extension. Is that correct?
    – Kusalananda
    May 16 at 5:56
  • Yes, that's correct. I think I know how to add Solid before the extension once I change the files with numbers.
    – shin
    May 16 at 5:59
  • This sounds like a job for mmv - I'd start with a dry-run such as mmv -n -m -p '[0-9]*' 'A#1#2', then remove the -n when I'm happy with the output. May 16 at 17:18

2 Answers 2

4

With zsh instead of bash, to rename <digits>.svg to A<digits>Solid.svelte:

autoload -Uz zmv

To autoload the zmv batch-renaming function (best in ~/.zshrc)

zmv -v '(<->).svg' 'A${1}Solid.svelte'

With perl-based renames, you can do the same (though without the safeguards of zmv) with:

rename -v 's/^(\d+)\.svg\Z/A${1}Solid.svelte/' [0-9]*.svg

The [0-9]*.svg expands to file names that start with a character in the 0 to 9 range (which includes but in some shells including bash is not limited to 0123456789) and end in .svg, but rename will only rename those that are made only of ASCII decimal digits (0123456789) followed by .svg.

Using a [0-9]*.svg glob also means the file names won't start with -, which means we don't need the -- which not all variants of perl-based rename support (while for others, omitting it introduces a command injection vulnerability!). Not all support -v either.

If the intent is to capitalise the root names of the files and append Solid.svelte, but also prepend A to file names starting with a digits, for instance for foo-bar.svg to become FooBarSolid.svelte, 0.svg A0Solid.svelte and 0foo-bar.svg A0FooBarSolid.svelte as your code seems to be trying to do, you'd do:

zmv -v '([0-9]#)(*).svg' '${1:+A$1}${${(C)2}//-}Solid.svelte'

Or with rename:

rename -v 's{^\./(\d*)(.*)\.svg\Z}{
    ($1 eq "" ? "" : "A$1") . ($2 =~ s/\w+/\u$&/gr =~ s/-//gr) . "Solid.svelte"
  }ge' ./*.svg

Bearing in mind that contrary to zmv, it only works properly on ASCII text (no captitalising of éric to Éric for instance).

Or you can extend the code you already have if you're happy with it by adding ; $_ = "A$_" if /^\d/ to prepend a A if the file name starts with a decimal digit.

1
  • This one worked nicely. Thanks. rename -v 's{^\./(\d*)(.*)\.svg\Z}{ ($1 eq "" ? "" : "A$1") . ($2 =~ s/\w+/\u$&/gr =~ s/-//gr) . "Solid.svelte" }ge' ./*.svg
    – shin
    May 16 at 6:36
0

Even complex file renaming can be done using pipeline including while loop with read:

ls -1 |
    grep '^[0-9]' |
    while read f
    do
        mv -v "$f" "A${f}otherText.svg"
    done

(The example above assumes that the names do not contain newlines and maybe few other funny characters.)

4
  • 2
    It's also dependant on the current value of $IFS. See Understanding "IFS= read -r line" May 16 at 16:11
  • Yes, I could add a note about that. In most cases, I deal with filenames without “funny” characters and therefore I do not need to use IFS. But if I get untrusted or unknown data, I am maybe even overly cautious about such names.
    – jiwopene
    May 16 at 16:14
  • You would be more likely to avoid problematic names if you just ls -1 -d [0-9]* - but it's better to steer clear of parsing the output of ls. You could use find instead and handle all names, for example. May 16 at 17:21
  • I use find quite frequently. And I would recommend against ls with glob. A for loop with glob would be enough in this case. (for file in [0-9]*)
    – jiwopene
    May 17 at 12:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.