Eu tenho algumas pastas com \n
caracteres, seus nomes.
por exemplo:
$ ls
''$'\n''Test'
Isso se refere a uma pasta com o nome do teste e uma linha vazia antes do nome.
Então, quando eu executo alguns scripts como este, em seu diretório pai:
while IFS= read -r d; do
rmdir $d
done < <(find * -type d)
Isto mostra:
rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory
Porque é executado duas vezes, uma vez ativada \n
e outra ativada Test
, porque o nome da pasta possui duas linhas.
Então, como posso resolver esse problema de maneira que, o script sabe que \nTest
é apenas uma pasta?
command-line
bash
scripts
Tara S Volpe
fonte
fonte
-print0
diretiva find e a-d
opção de leitura. Veja stackoverflow.com/a/40189667/7552find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done
comando tem esta saídarmdir: failed to remove 'Test': No such file or directory
.rmdir "$file"
Respostas:
Você tem apenas um comando lá, portanto, é suficiente chamar
find
com-exec
sinalizaçãormdir
:Ou use a
-delete
opção como emfind -type d -delete
, mas ela não funcionará com diretórios não vazios. Para isso você também precisará de uma-empty
bandeira. Observe também,-delete
implica-depth
que pode ser pulado. Assim, outra alternativa viável que mantém tudo como um processo:Se o diretório não estiver vazio, use
rm -rf {} \;
. Para isolar apenas diretórios com\n
in filename, podemos combinar a cotação ANSI-C do bash$'...'
com a-name
opção:POSIX-ly, nós poderíamos lidar com isso desta maneira:
Vale ressaltar que, se seu objetivo é a remoção de diretórios,
-delete
é suficiente; no entanto, se você deseja executar um comando no diretório,-exec
é o mais apropriado.Veja também
find
saída?fonte
rm -rf
com cuidado . ; P Nãofind
tem uma-delete
opção entre? Exclui diretórios vazios e gera erros para diretórios não vazios, comormdir
- pode ser mais barato.-delete
não removemos diretórios não vazios. Portanto, o uso cuidadoso de #rm -rf
find
comandos sem qualquer carga destrutiva (ou seja, remover o-delete
ou-exec whatever \;
) para verificar se a lista de arquivos afetados é realmente correto e não contém material que não deve ficar excluído ...find
. Use-exec rmdir {} +
para agrupar vários argumentos em umarmdir
linha de comando. E BTW ", mas não funcionará com diretórios não vazios " .rmdir
Também se aplica , portanto, isso não é realmente uma diferença-delete
. É uma diferença derm -r
.find -type d -empty -delete
(-delete
implica-depth
).Você pode usar globs de shell em vez de
find
:O shell glob
*/
corresponde a todas as pastas no diretório atual. Essa construção de loop for cuida da divisão correta da palavra automaticamente.Observe que, dependendo das opções do shell, isso pode ignorar pastas ocultas (nome começando com a.). Esse comportamento pode ser alterado para coincidir com todos os arquivos para a sessão atual usando o comando
shopt -s dotglob
.Também não se esqueça de sempre citar suas variáveis.
fonte
find
fazshopt -s globstar
e usando um**/*/
glob.Ambas as respostas escritas até o momento chamam
rmdir
uma vez por diretório, mas, comormdir
pode levar vários argumentos, eu me pergunto: Não há uma maneira mais eficiente?Alguém poderia simplesmente fazer
e essa é definitivamente a maneira mais fácil e eficiente, mas pode gerar um erro no caso de muitos diretórios (consulte Qual é o tamanho máximo dos argumentos da linha de comando no gnome-terminal? ). Se você deseja que essa abordagem funcione recursivamente, ative a
globstar
opção de shell comshopt -s globstar
e use em**/*/
vez de*/
.Com o GNU
find
(e se não queremos apenas usar-delete
), poderíamos fazerque constrói a linha de comando "da mesma maneira que
xargs
constrói suas linhas de comando" (man find
). Substituto-depth
para-maxdepth 1
se você não quer que ele funcione de forma recursiva.Uma terceira maneira brilhante e IMO é explicada por steeldriver nesta resposta :
Isso usa o shell interno
printf
para criar uma lista de argumentos delimitada a zero; essa lista é então canalizada para axargs
qual chamarmdir
exatamente quantas vezes for necessário. Você pode fazê-lo funcionar recursivamente comshopt -s globstar
e em**/*/
vez de*/
como acima.fonte
find
é recursivo, mas o loop do OP não. Para replicar esse comportamento, usefind -maxdepth 1 -type d -exec rmdir {} +
. (-depth
é redundante nesse caso.) Um truque legalprintf
para imitarfind -print0
, eu nunca tinha visto isso antes.ls
e owhile
loop, eu perdi que eles estavam redirecionando de uma substituição processo comfind
em vez de tubulaçãols
para o loop e simplesmente não mostrá-lo por algum motivo. Issofind *
está realmente enterrado. Sim, é recursivo e falhará se houver muitas entradas de diretório no diretório, incluindo os não-diretórios, porque ele não é usado*/
.find .
seria muito melhor, porquefind
é mais rápidostat
que a expansão glob do bash.