com mv
cannot move 'foo' to a subdirectory of itself
é inofensivo neste caso, você pode ignorá-lo. Quero dizer mv
vai mover o resto apesar do aviso. No entanto, o status de saída não será 0
, isso pode ser um grande obstáculo em scripts nos quais você deseja interromper ou executar uma ação de correção se mv
não for bem-sucedido.
Isso já foi dito em um comentário : você pode silenciar mv
redirecionando stderr com 2>/dev/null
; outros avisos ou erros também serão redirecionados.
Eu acho que você não pode facilmente "refinar o padrão para limitar a fonte a arquivos e diretórios". Ainda assim, você pode adotar uma abordagem que não corresponda ao literal foo
. A abordagem a seguir não tem nada a ver com arquivos ou diretórios; apenas com nomes, porque globs lidam com nomes; então pode não ser suficiente em alguns casos.
O *foo*
glob corresponde a quatro tipos de objetos disjuntivos:
-
foo
em si - foo apenas com prefixo, como
bar-foo
- você pode combiná-los por*?foo
- foo com prefixo e postfix, como
bar-foo-baz
-*?foo?*
- foo apenas com postfix, como
foo-baz
-foo?*
Para excluir foo
, você só precisa dos últimos três (2-4), então a primeira abordagem pode ser:
mv *?foo *?foo?* foo?* foo/
A menos que você tenha a opção nullglob
shell, qualquer padrão precisa corresponder a algo, caso contrário, ele será passado para mv
literalmente. Você não quer isso. A solução é executar o seguinte comando de antemão:
shopt -s nullglob
Esta opção de shell fará com que qualquer glob incomparável seja expandido para nada. Eu aconselho você a pesquisar a opção dotglob
também.
Observe que *?foo*
corresponde (2-3). Da mesma forma *foo?*
corresponde (3-4). Além disso, considere --
informar mv
de que todos os argumentos a seguir não são opções. Dessa forma, um arquivo como --foo
não será interpretado como uma opção (desconhecida). Isso leva a dois comandos melhores:
mv -- *?foo* foo?* foo/
ou
mv -- *?foo *foo?* foo/
Não importa qual você escolher. Apenas não use mv *?foo* *foo?* foo/
; ele passará (por exemplo) bar-foo-baz
para mv
duas vezes (ou seja, como dois argumentos separados), gerando assim um erro quando a ferramenta tentar mover este objeto pela segunda vez.
Quando nenhuma correspondência for encontrada, meus comandos mv
se degenerarão para mv foo/
e lançarão um erro. Seu comando mv
original (com nullglob
unset) obteria o literal *foo*
e lançaria outro erro.
Exemplo de sessão do console:
$ shopt -s nullglob
$ mkdir foo
$ touch bar-foo bar-foo-baz foo-baz xyfooz.tex ./--foo
$ mv -v -- *?foo* foo?* foo/
'bar-foo' -> 'foo/bar-foo'
'bar-foo-baz' -> 'foo/bar-foo-baz'
'--foo' -> 'foo/--foo'
'xyfooz.tex' -> 'foo/xyfooz.tex'
'foo-baz' -> 'foo/foo-baz'
$
hack simples
Digamos que dummy
não exista.
mv foo dummy
mv *foo* dummy/
mv dummy foo
Renomear um diretório deve ser muito rápido em sistemas de arquivos baseados em inode. Programas com arquivos de foo/
já abertos não devem interferir nem quebrar, porque é o inode que importa. No entanto, se algum programa precisar abrir um arquivo (pelo caminho incluindo foo/
) entre o primeiro e o terceiro mv
, ele falhará. Outros efeitos colaterais podem ocorrer (imagine um programa de terceiros recriando foo/
nesse meio tempo), e é por isso que eu chamo essa abordagem de hack. Pense duas vezes antes de usá-lo.
Com find
de qualquer maneira
A inclusão de arquivos de diretórios é um trabalho para find
. O que você fez com find
é basicamente o caminho certo. O que você quer fazer (e o que eu fiz acima) com mv
e shell globbing parece ... bem, "menos certo" no máximo. Este é o seu comando:
find . -maxdepth 1 -type f -name '*foo*' -exec mv {} foo \;
Este find
executará um mv
separado para cada arquivo correspondente, todo o comando terá um desempenho ruim. Por esse motivo, pode-se querer mudar para um único mv
. Se esta é sua linha de pensamento (e seus mv
e find
são ricos o suficiente), então você deve considerar este modo "muito correto":
find . -maxdepth 1 -type f -name '*foo*' -exec mv -t foo/ -- {} +
As vantagens sobre o comando find
e / ou sobre mv
sem formatação com glob (s):
- um único
mv
pode ter vários arquivos para trabalhar; - ainda, se houver muitos arquivos para uma linha de comando,
find
executarámv
process (es) adicionais; - em um caso em que nenhum arquivo corresponde ao padrão,
mv
não será executado; - obrigado a
--
um arquivo como--foo
não será interpretado como uma opção (desconhecida) paramv
;