Se a instrução para dizer se um arquivo está em um diretório [duplicado]

1

Estou escrevendo um script bash e quero que ele me diga se os nomes dos arquivos em um diretório aparecem em um arquivo de texto e, se não, remova-os.

Algo parecido com isto:

counter = 1
numFiles = ls -1 TestDir/ | wc -l 
while [$counter -lt $numFiles]
do
     if [file in TestDir/ not in fileNames.txt]
     then
          rm file
     fi
     ((counter++))
done
    
por J. Tate 16.03.2018 / 13:21

3 respostas

3

Em vez de salvar a lista de arquivos em uma variável, faça um loop pelos nomes:

for name in TestDir/*; do
    # the rest of the code
done

Para testar se $name ocorre no fileNames.txt , use grep -q :

for name in TestDir/*; do
    if ! grep -qxF "$name" fileNames.txt; then
        echo rm "$name"
    fi
done

O -F faz com que grep execute uma comparação de string em vez de uma correspondência de expressão regular. Com -q não obtemos resultados de grep , apenas um status de saída que podemos usar com a instrução if (true se a string foi encontrada, mas o ponto de exclamação inverte o sentido do teste). O -x informa grep que a string $name precisa corresponder a uma linha inteira, do início ao fim, não apenas uma parte de uma linha.

Eu protegi o rm real com echo . Execute e certifique-se de que os arquivos corretos sejam excluídos.

Se os nomes dos arquivos estiverem listados sem o caminho TestDir , altere $name no comando grep para ${name##*/} :

for name in TestDir/*; do
    if ! grep -qxF "${name##*/}" fileNames.txt; then
        echo rm "$name"
    fi
done

Isso procurará a parte do nome do arquivo do caminho em $name em vez do caminho completo, incluindo TestDir .

    
por 16.03.2018 / 13:34
2

com zsh :

expected=(${(f)"$(<fileNames.txt)"}) || exit
cd TestDir || exit
actual=(*(D))
superfluous=(${actual:|expected})
if (($#superfluous)) {
  echo These files are not in the expected list:
  printf ' - %q\n' $superfluous
  read -q '?Do you want to delete them? ' && rm -rf -- $superfluous
}
    
por 16.03.2018 / 13:46
2

Aqui está uma versão funcional usando sua abordagem:

#!/bin/bash
fileList="$1"
targetDir="$2"

## Read the list of files into an associative array
declare -A filesInFile
while IFS= read -r file; do
  filesInFile["$file"]=1
done < "$fileList"

## Collect the files in the target dir
filesInDir=("$targetDir"/*);

for file in "${filesInDir[@]}"; do
  file=${file##*/}; # get the name of the file; remove path
  ## If this file has no entry in the array, delete
  if [[ -z "${filesInFile[$file]}" ]]; then
      echo "rm $file"
  fi
done

Remova o echo para realmente excluir os arquivos. Note que não estou verificando se o número de arquivos é diferente, já que não parece muito útil, já que o número de arquivos pode ser o mesmo, mas você ainda pode ter arquivos cujo nome não esteja na lista.

    
por 16.03.2018 / 13:50