Maneira simples de excluir um arquivo e todos os seus links (simultaneamente)

2

Encontrei muitas perguntas sobre como excluir apenas links simbólicos ou excluir links simbólicos com base em seu conteúdo, mas ninguém perguntou como fazer o que eu quero fazer.

Tome o seguinte exemplo

file-l -> ../file
file-l2 -> ../file

Desejo excluir file , file-l e file-l2 de uma só vez, sem conhecer a localização dos outros arquivos, preferencialmente especificando file como argumento. (imagine que eu tenha mais de 100 links para o mesmo arquivo em lugares aleatórios em todo o sistema de arquivos). Primeiramente, eu preferiria um script de shell ou um programa interno, mas os programas externos também estão bem.

Depois que unlink e rm não forneceram a funcionalidade desejada, inicialmente tive a ideia de usar inodes ou stat ou algo assim, mas ...

$ stat test
  File: ‘test’
  Size: 0           Blocks: 0          IO Block: 4096   regular empty file
Device: 811h/2065d  Inode: 27001032    Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/  braden)   Gid: ( 1000/  braden)
Access: 2015-08-30 21:30:35.578786598 -0600
Modify: 2015-08-30 21:30:35.578786598 -0600
Change: 2015-08-30 21:30:35.578786598 -0600
 Birth: -
$ stat test-l
  File: ‘test-l’ -> ‘test’
  Size: 4           Blocks: 0          IO Block: 4096   symbolic link
Device: 811h/2065d  Inode: 27001033    Links: 1
Access: (0777/lrwxrwxrwx)  Uid: ( 1000/  braden)   Gid: ( 1000/  braden)
Access: 2015-08-30 21:30:42.074786598 -0600
Modify: 2015-08-30 21:30:41.426786598 -0600
Change: 2015-08-30 21:30:41.426786598 -0600
 Birth: -

Não só o link simbólico tem um inode único (isso é um dado), mas não parece haver nenhuma informação além do nome do arquivo que eu possa usar para concluir que "sim, este é um link simbólico para o arquivo I quer". Se eu usar o nome do arquivo, então, eu tenho que lidar com o regex-hell. Isso é algo que eu pessoalmente gostaria de evitar, pois, na prática, os nomes dos arquivos contêm caracteres como espaço, meta-caracteres ( ?![]{}., ) e caracteres unicode.

Eu também gostaria de evitar coisas como awk, perl, hacks loucos que exploram bugs / falhas de design no bash 4.2.XX, e outras coisas estranhas que provavelmente não funcionariam corretamente (se forem) em uma nova instalação de, por exemplo, Arch Linux ou CentOS. Basicamente eu deveria ser capaz de rodar o dito comando / script fora da caixa em um sistema que não tenha awk, sed, perl, ruby e python, e execute o bash-4.1 como seu shell.

Se isso não for possível, prefiro pelo menos que o script / comando seja onipresente, como vi , cat , ls , etc.

O mínimo dos meus requisitos é que a solução:

  • pode excluir um arquivo e todos os seus links simbólicos apenas com o arquivo original como um argumento
  • pode fazê-lo sem saber os nomes ou localizações dos referidos links simbólicos
  • pode fazer isso em links simbólicos de nomes variados e locais variados
  • funciona em uma instalação nova e mínima do Arch Linux (ou sistema mínimo semelhante)
  • não é um código de golfe
  • regexes razoáveis e fáceis de entender

É assim que tento projetar meus próprios scripts, por isso considero razoável. Mas, no entanto, espero que não seja muito exigente.

Obrigado.

Edit: Eu sinto que sou obrigado a mostrar o meu trabalho. Apenas solicitando um script me faz sentir como um idiota. Então, é isso que eu tenho:

get_lnk(){
    gl_file=""
    gl_orig_a=( $(ls -l "$gl_file") )
    gl_orig="${gl_orig_a[-1]}"
}
for i in *; do 
    get_lnk "$i"
    echo "file: $gl_file"
    echo "links to: $gl_orig"
    echo
done

# output:

file: file-l
links to: ../file

file: file-l2
links to: ../file

Isto imprime o nome do symlink e o nome do arquivo para o qual ele aponta. Isso é realmente o oposto do que estou tentando fazer, mas é razoavelmente útil (quando todos os links estão no mesmo lugar).

    
por Braden Best 31.08.2015 / 05:55

1 resposta

2

Digamos que você tenha um arquivo chamado file1 in ~/tmp e digamos que você queira remover recursivamente todos os links simbólicos para file1 in ~/tmp ;

Usando find :

find ~/tmp -lname ~/tmp/file1 -exec rm {} +
  • ~/tmp : especifica o caminho para a hierarquia de diretórios na qual pesquisar;
  • -lname : pesquisa somente links simbólicos vinculados a ~/tmp/file1 ;
  • -exec rm {} + : remove todos os resultados;

Exemplo de saída em uma hierarquia de diretório de teste:

user@debian ~/tmp % tree
.
├── 1
│   ├── 2
│   │   ├── 3
│   │   │   ├── link3-1 -> /home/user/tmp/file1
│   │   │   └── link3-2 -> /home/user/tmp/file2
│   │   ├── link2-1 -> /home/user/tmp/file1
│   │   └── link2-2 -> /home/user/tmp/file2
│   ├── link1-1 -> /home/user/tmp/file1
│   └── link1-2 -> /home/user/tmp/file2
├── file1
└── file2

3 directories, 8 files
user@debian ~/tmp % find . -lname ~/tmp/file1 -exec rm {} +
user@debian ~/tmp % tree
.
├── 1
│   ├── 2
│   │   ├── 3
│   │   │   └── link3-2 -> /home/user/tmp/file2
│   │   └── link2-2 -> /home/user/tmp/file2
│   └── link1-2 -> /home/user/tmp/file2
├── file1
└── file2

3 directories, 5 files
    
por kos 10.09.2015 / 07:44