Há uma resposta do SuperUser , que renomeia nomes de arquivos que contêm espaços em branco:
for f in *\ *; do mv "$f" "${f// /_}"; done
A parte que não entendo é *\ *
.
O autor escreveu que:
*\ *
Seleciona todos os arquivos com um espaço no nome como entrada para o loop for. O padrão X seleciona todos os arquivos com X no nome e, para o caractere especial espaço, precisamos usar uma barra para que o bash não o trate como uma separação de argumentos.
Já que *
não corresponde a um espaço, por que *\ *
também corresponde a arquivos com vários caracteres de espaço quando ele só tem um espaço?
O padrão de globbing tem duas partes
*\ *
.Você também pode escrever
*\ *
como*' '*
ou mesmo*" "*
, e em qualquer caso o espaço é tratado como qualquer caractere imprimível, em vez do separador de token que é na sintaxe do shell.Observe também, em resposta a uma confusão na sua pergunta, que isso
*
pode corresponder a um espaço tão bem quanto a qualquer outro caractere (ou conjunto de caracteres). O padrão*\ *
corresponde a qualquer coisa, depois a um espaço, depois a qualquer coisa , então garante que deve haver pelo menos um espaço em nomes de arquivo que correspondam.Por fim, nomes de arquivos com espaços não são um problema, desde que seu código seja bem escrito. Por exemplo, isso processará qualquer nome de arquivo, independentemente dos caracteres que ele contém:
* Na verdade, se você estiver em uma localidade Unicode, poderá ter problemas com algumas sequências de bytes que não correspondem a caracteres Unicode válidos. Você pode contornar isso configurando
LC_CTYPE=C
‡ É mais fácil,
printf '>> %s<<\n' *
mas isso não ilustraria o ponto que eu queria fazerIsso ocorre porque
*
corresponde a qualquer string, incluindo strings com espaços.Em vez de um espaço, vamos usar
X
. Suponha que temos todos estes arquivos no diretório atual:abc
X
defg
hijk
lmXXnop
qXrsXt
uvwXX
(Você pode fazê-los executando
touch abc X defg hijk lmXXnop qXrsXt uvwXX
.)Agora o padrão de globbing
*
corresponde a todos eles:Se eu adicionar um
X
, o padrão significa "qualquer coisa que termine emX
":(Observe que isso inclui
uvwXX
, que tem doisX
s. Isso ocorre porque*
corresponde auvwX
.)Se eu adicionar outro
X
, o padrão significa "qualquer coisa que termine em doisX
's":Mas se eu adicionar outro
*
, o padrão significa "qualquer coisa que contenha pelo menos umX
":