Remover arquivos que não foram nomeados “today.md” [duplicado]

7

Eu tenho uma série de arquivos markdown no diretório de trabalho:

$ ls *.md
csv_reader.md  egrep.md  find.md  found_pdfs.md  osPathSep_help.md  readme.md  smtplib_help.md  today.md

Eu quero removê-los, exceto "today.md"

#!/usr/local/bin/bash
for i in ./*.md ; do
    if [[ $i != "today.md" ]]; then
        echo $i
    fi
done

Execute e obtenha

$ bash bash/remove_files.sh
./csv_reader.md
./egrep.md
./find.md
./found_pdfs.md
./osPathSep_help.md
./readme.md
./smtplib_help.md
./today.md

No entanto, os comandos estruturados não são úteis na linha de comando, como eu poderia realizar essa tarefa com comandos mais curtos

    
por avirate 30.10.2018 / 23:53

5 respostas

19

Use uma correspondência negativa (requer shopt -s extglob , mas possivelmente já definido):

rm !(today).md

(primeiro você pode usar ls em vez de rm para verificar o resultado).

Muita energia em extglob , você também pode fazer

rm !(yesterday|today).md

se você quiser poupar dois arquivos.

    
por 31.10.2018 / 00:54
12

find . -maxdepth 1 -name '*.md' ! -name today.md -type f -print

Deve encontrar todos os arquivos ( -type f ) no diretório atual ( . - ou colocar explicitamente um nome de diretório lá) apenas ( -maxdepth 1 impede seguintes subdiretórios ) que terminam em .md ( -name '*.md' ), excluindo ( ! ) o arquivo today.md .

Não se esqueça de incluir as aspas simples em torno de '*.md' , para que seu shell não tente expandi-lo para a lista de arquivos .md no diretório atual antes de executar find .

Ele irá imprimir a lista de arquivos a serem excluídos. Altere -print para -delete para excluí-los.

    
por 31.10.2018 / 00:00
9

As soluções acima são melhores, mas o motivo pelo qual seu código não está funcionando é devido à comparação.

"./ today.md" não é igual a "today.md".

    
por 31.10.2018 / 01:23
3

Você pode achar que é mais curto usar recurso de globalização estendida do bash para excluir o arquivo que você não quer :

shopt -s extglob
echo rm -- !(today).md

O acima (depois de remover o echo para testes) diz que corresponde a qualquer coisa, exceto today seguido por .md .

Seu exemplo não corresponde a arquivos de ponto por padrão. você pode mudar esse comportamento com shopt dotglob , se desejado

Seu script não funcionou como escrito porque o padrão glob que você usou (apropriadamente) prefixou os nomes dos arquivos com ./ ; portanto, seu teste interno deve ser comparado com ./today.md .

    
por 31.10.2018 / 00:50
-1

O Unix é famoso por ter várias maneiras de realizar as mesmas tarefas simples. Algumas pessoas adoram usar sed , mas eu gosto de grep , então se eu estivesse apenas digitando na linha de comando, usaria:

rm -i 'ls *.md | grep -v '^today.md$''
  1. ls *.md lista todos os arquivos cujos nomes terminam com .md .
  2. | canaliza os resultados de ls para o próximo comando, mas como efeito colateral, faz com que ls liste os arquivos em várias linhas, 1 por linha.
  3. grep -v '^today.md$' ecoa as linhas que não correspondem exatamente a today.md
  4. rm -i então pega os resultados (porque os comandos estão dentro dos backticks) que perguntam se você quer deletá-los, 1 por 1. Eu sempre faço isso quando estou usando uma lista gerada de arquivos, caso algo dê errado com o arquivo. gerador. Você pode usar rm sem o -i para excluir os arquivos sem perguntar, mas isso é mais arriscado e também não fornece uma lista de quais arquivos foram excluídos.
por 31.10.2018 / 02:26