Você poderia fazer algo como:
rename 's/[<>:"\|?*]/_/g' /path/to/file
Isso substituirá todos esses caracteres por _
. Note que você não precisa substituir /
, já que é um caractere inválido para nomes de arquivos em ambos os sistemas de arquivos, mas é usado como o separador de caminho Unix.
Estenda para um diretório e todo o seu conteúdo com:
find /path/to/directory -depth -exec rename 's/[<>:"\|?*]/_/g' {} +
Observe que /
(que marca o final do padrão) e \
estão com escape. Para manter a exclusividade, você pode adicionar um prefixo aleatório a ele:
$ rename -n 's/[<>:"\/\|?*]/_/g && s/^/int(rand(10000))/e' a\b
a\b renamed as 8714a_b
Uma solução mais completa deve, pelo menos:
- Converta todos os caracteres para o mesmo caso
- Use um sistema de contagem sã
Isso significa que foo.mp3
não deve se tornar foo.mp3.1
, mas foo.1.mp3
, pois o Windows depende mais de extensões.
Com isso em mente, escrevi o seguinte script. Eu tentei ser não-destrutivo, usando um caminho de prefixo no qual eu posso copiar os arquivos renomeados, em vez de modificar o original.
#! /bin/bash
windows_chars='<>:"\|?*'
prefix="windows/"
# Find number of files/directories which has this name as a prefix
find_num_files ()
(
if [[ -e $prefix ]]
then
shopt -s nullglob
files=( "$prefix-"*"" )
echo ${#files[@]}
fi
)
# From http://www.shell-fu.org/lister.php?id=542
# Joins strings with a separator. Separator not present for
# edge case of single string.
str_join ()
(
IFS=${1:?"Missing separator"}
shift
printf "%s" "$*"
)
for i
do
# convert to lower case, then replace special chars with _
new_name=$(tr "$windows_chars" _ <<<"${i,,}")
# if a directory, make it, instead of copying contents
if [[ -d $i ]]
then
mkdir -p "$prefix$new_name"
echo mkdir -p "$prefix$new_name"
else
# get filename without extension
name_wo_ext=${new_name%.*}
# get extension
# The trick is to make sure that, for:
# "a.b.c", name_wo_ext is "a.b" and ext is ".c"
# "abc", name_wo_ext is "abc" and ext is empty
# Then, we can join the strings without worrying about the
# . before an extension
ext=${new_name#$name_wo_ext}
count=$(find_num_files "$name_wo_ext" "$ext")
name_wo_ext=$(str_join - "$name_wo_ext" $count)
cp "$i" "$prefix$name_wo_ext$ext"
echo cp "$i" "$prefix$name_wo_ext$ext"
fi
done
Em ação:
$ tree a:b
a:b
├── b:c
│ ├── a:d
│ ├── A:D
│ ├── a:d.b
│ └── a:D.b
├── B:c
└── B"c
└── a<d.b
3 directories, 5 files
$ find a:b -exec ./rename-windows.sh {} +
mkdir -p windows/a_b
mkdir -p windows/a_b/b_c
mkdir -p windows/a_b/b_c
cp a:b/B"c/a<d.b windows/a_b/b_c/a_d.b
mkdir -p windows/a_b/b_c
cp a:b/b:c/a:D.b windows/a_b/b_c/a_d-0.b
cp a:b/b:c/A:D windows/a_b/b_c/a_d
cp a:b/b:c/a:d windows/a_b/b_c/a_d-1
cp a:b/b:c/a:d.b windows/a_b/b_c/a_d-1.b
$ tree windows/
windows/
└── a_b
└── b_c
├── a_d
├── a_d-0.b
├── a_d-1
├── a_d-1.b
└── a_d.b
2 directories, 5 files
O script está disponível em meu repositório do Github .