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:
-
fooem 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
mvpode ter vários arquivos para trabalhar; - ainda, se houver muitos arquivos para uma linha de comando,
findexecutarámvprocess (es) adicionais; - em um caso em que nenhum arquivo corresponde ao padrão,
mvnão será executado; - obrigado a
--um arquivo como--foonão será interpretado como uma opção (desconhecida) paramv;