4

This thread (https://superuser.com/questions/659876/how-to-rename-files-and-replace-characters) has proven bountiful and does what I need it to do, except, I need to replace just the first instance of a character in a filename.

How can I make it so that this:

for f in *:*; do mv -v "$f" $(echo "$f" | tr '.' '_'); done

Only replaces the first instance of . in a filename, with a filename such as:

2022-10-07T071101.8495077Z_QueryHistory.txt
2

2 Answers 2

5

Unfortunately, the method you tried is more complex than it needs to be, and fragile (it breaks if file names contain certain special characters). Here's a simpler method relying on parameter expansion to transform the file name:

for f in *; do mv -v -- "$f" "${f/./_}"; done   # replace the first .
for f in *; do mv -v -- "$f" "${f//./_}"; done  # replace every .

This requires bash, ksh or zsh as the shell: other shells such as dash (which is Ubuntu's /bin/sh, so commonly used for scripting, but hardly ever used interactively) don't have the ${VARIABLE/PATTERN/REPLACEMENT} form of parameter expansion.

Alternatively, you can use prename (apt install rename):

rename 's/\./_/' *     # replace the first .
rename 's/\./_/g' *    # replace every .

Alternatively, you can use zsh's zmv:

autoload -U zmv   # put this in your .zshrc
zmv '*' '${f/./_}'        # replace the first .
zmv -W '*.*.*' '*_*.*'    # replace the next-to-last .
zmv '*' '${f//./_}'       # replace every .

All the snippets in my answer skip files whose name begins with a dot.

2
  • Amazing -- any chance you comment / update for the following situation: if the filename has two periods, execute the rename operation, else do nothing (so repeated execution of the script does not remove the file-extension.
    – John Stud
    Commented Oct 7, 2022 at 18:25
  • 1
    @JohnStud Instead of replacing all files matching *, only replace files matching *.*.* (or some more precise pattern). The “replace the next-to-last .” solution already does this. Commented Oct 7, 2022 at 19:59
0

Using Perl's rename commandline:

    rename -n 's/\./_/' ./2022-10-07T071101.8495077Z_QueryHistory.txt

Remove -n (aka dry-run) when the output looks satisfactory.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .