1

I have a dir with tons of files inside which have been named in malformed such as file..txt ,file2..txt ,etc...

So how to easily remove this second . from file names?

Any applicable method is appreciated including awk,sed,grep,etc...

  • 3
    can it be more than two dots in the file name ? – heemayl Jul 2 '15 at 10:31
  • 2
    No, all files have exactly two dots only – Maythux Jul 2 '15 at 10:32
  • .\n. isn't .. – A.B. Jul 2 '15 at 12:34
  • Not from me. :\ – A.B. Jul 2 '15 at 13:49
5

Using rename (as per heemayl's suggestion I narrowed down the globbing only to filenames ending exactly with ..txt):

rename -n 's/(.*)\./$1/' *..txt

This will match the filename until the last dot and replace the match with everything but the last dot.

If the result is the expected one, remove the -n option:

rename 's/(.*)\./$1/' *..txt
  • 1
    no it may happen to have some dots in file name, – Maythux Jul 2 '15 at 10:43
  • 1
    kos, Rather than using *, use *..txt to get the files as only * will cause problem when you have any file with only one . (i mean in general case) – heemayl Jul 2 '15 at 10:49
  • 2
    Doesn't work with newlines in the filenames – A.B. Jul 2 '15 at 10:56
  • 1
    @A.B. Why does this not work when there are new lines in the file name? It looks clean to me (on that issue—there may be other issues to deal with). – Jonathan Leffler Jul 2 '15 at 13:34
  • 1
    already upvoted my friend. ;) – A.B. Jul 2 '15 at 14:03
4

Another rename variant:

rename 's/\Q.././' *..txt

using \Q avoids escaping the dots (See http://perldoc.perl.org/perlretut.html)

  • And with newlines in a filename? ;) – A.B. Jul 2 '15 at 11:36
  • @A.B. it works, you only get a warning about Unsuccessful stat – Sylvain Pineau Jul 2 '15 at 11:39
4

I have a working solution, still working for better one:

for f in *; do mv $f ${f%.txt}txt; done

Thank to @heemayl note:

Rather than using *, use *..txt to get the files as only * will cause problem when you have any file without . and with only one

So becomes:

for f in *..txt; do mv $f ${f%.txt}txt; done
  • 1
    Rather than using *, use *..txt to get the files as only * will cause problem when you have any file without . and with only one . – heemayl Jul 2 '15 at 10:47
  • @heemayl Perfect note, thanks, I just put * assuming i know file names hierarchy, but you are totally alright in general – Maythux Jul 2 '15 at 10:48
  • Same here, not with newlines in a filename – A.B. Jul 2 '15 at 11:35
2

You may try the reverse order. This works if the filename contains newline characters.

rename 's/\.([^.]+)$/$1/' *..txt
  • ya.. you may try rename 's/\.([^.]+)$/$1/s' *..txt also. – Avinash Raj Jul 2 '15 at 11:39
2

The very simple way to do this just run the following command inside the directory which contains the filenames in the format u mentioned above

rename 's/\.+txt/\.txt/' *
  • not for 'foo..bar..txt' – A.B. Jul 3 '15 at 11:26
  • @A.B. edited is that fine – jerry Jul 3 '15 at 11:30
  • Yes, it works now. – A.B. Jul 3 '15 at 11:42
1

Filenames can contains a newline character, therefore:

find . -maxdepth 1 -type f -print0 | while read -d $'\0' f; do mv "$f" "${f%.txt}txt"; done

Example

$ find -exec  printf "%s ---" {} \;
. ---./foo
..txt ---./foo..txt ---

$ find . -maxdepth 1 -type f -print0 | \
    while read -d $'\0' f; do mv "$f" "${f%.txt}txt"; done

$ find -exec  printf "%s ---" {} \;
. ---./foo
.txt ---./foo.txt ---
  • @Maythux The ? is a newline char. – A.B. Jul 2 '15 at 12:28
  • No, ls shows a ?, I have changed my example. – A.B. Jul 2 '15 at 12:31
  • touch "hello?..?txt" – Maythux Jul 2 '15 at 12:38
  • @Maythux no, touch "hello<RETURN>..txt" – A.B. Jul 2 '15 at 14:01
1

This works quite well if there's no single-dot files:

for file in *; do mv "$file" "${file%%.*}${file#*.}"; done
  • No awk version? (already upvoted my friend ;) ) – A.B. Jul 2 '15 at 14:08

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.