Ajuda com um script Bash ou algum programa para classificar arquivos e mover para pastas diferentes

0

Existe alguém lá fora que possa me ajudar a classificar alguns arquivos com um script bash ou comandos de terminal (ou mesmo um pequeno programa Java) que podem ser usados para classificar e mover arquivos para novas pastas? Eu tenho tentado por dias, mas não descobri isso.

Eu tenho uma pasta chamada "páginas da Web" com centenas de arquivos html. Grosso modo, eles são divididos em três categorias, então eu precisarei executar um script três vezes com variáveis diferentes ou um script que possa fazer toda a ordenação e se mover de uma só vez.

Eu quero procurar por determinadas cadeias de caracteres nos arquivos e, em seguida, enviar os arquivos que correspondem a novas pastas. Para simplificar, algumas das páginas da web são sobre política, algumas sobre negócios e outras sobre computadores. Então, digamos que eu quero pesquisar todos os arquivos na pasta "páginas da Web" para as palavras "eleição", "mercado de ações" e "código aberto" e mover os arquivos contendo a palavra "eleição" para uma pasta chamada "política" , os arquivos contendo a palavra "mercado de ações" para uma pasta chamada "business" e os arquivos contendo o termo "open source" para uma pasta chamada "computadores".

Como eu disse, tentei descobrir, mas acabei sendo ridicularizado por meus esforços. Eu não sou especialista. Obrigado!

    
por David 30.03.2015 / 18:58

3 respostas

2

Suponha que você tenha os seguintes arquivos no diretório atual:

  • a/sm1 , com o conteúdo "um mercado de ações b"
  • b/sm2 , com o conteúdo "x stock market y"
  • sm3 , que não contém "mercado de ações"
  • destination , um diretório para o qual você deseja mover arquivos que contêm "mercado de ações" .

Vamos encontrar todos os arquivos (do tipo f = file) no diretório atual ( . ):

$ find . -type f
./a/sm1
./sm3
./b/sm2

Mas sm3 não contém "mercado de ações", não queremos isso. Nesta lista de arquivos que temos agora, vamos procurar "mercado de ações" e exibir apenas os arquivos correspondentes:

$ find . -type f | xargs grep --files-with-matches "stock market"
./a/sm1
./b/sm2

Agora vamos pegar cada um dos arquivos que temos e movê-los para o diretório destination :

$ for f in $(find . -type f | xargs grep --files-with-matches "stock market"); do mv $f destination/; done

Certifique-se de ter um backup antes de executá-lo, caso não o mova como deseja.

    
por Cos64 30.03.2015 / 20:06
2

Eu acho que algumas magias simples podem fazer o truque:

#!/bin/bash
dir1=""
dir2=""
dir3=""
shopt -s nullglob
for i in *.html)
    do if [ "$(grep 'keyword1' $i)" != "" ]; then
        mv -vf "$i" "$dir1"
    elif [ "$(grep 'keyword2' $i)" != "" ]; then
        mv -vf "$i" "$dir2"
    elif [ "$(grep 'keyword3' $i)" != "" ]; then
        mv -vf "$i" "$dir3"
    else
        echo "$i">>nomatch
    fi
done
cat nomatch
    
por Wilhelm Erasmus 30.03.2015 / 20:29
2

Aqui estão algumas maneiras de fazer o que você quer:

1. %código%

find . -iname '*html' -type f -exec grep -q election "{}" \; -and -exec mv {} politics/ \; 

Explicação

Aqui, estamos usando a opção find do find:

-exec command ;
      Execute  command;  true  if 0 status is returned.  All following
      arguments to find are taken to be arguments to the command until
      an  argument  consisting of ';' is encountered.  The string '{}'
      is replaced by the current file name being processed

Assim, o primeiro -exec pesquisa o arquivo (aqui, representado por -exec ) para {} e o segundo pré-forma o movimento. O election garante que o segundo -and seja executado somente se o primeiro for bem-sucedido, se o arquivo corresponder ao padrão.

2. -exec & concha.

Esta é a mesma abordagem básica que a da resposta do Cos64, mas com algumas melhorias.

find . -iname '*html' -type f -print0 | 
    while IFS= read -r -d '' file; do 
        grep -q election "$file" && mv "$file" politics/
    done

Explicação

  • O comando find localizará todos os arquivos ( find ) cujo nome terminará em -type f (ou .html , o .HTML não diferencia maiúsculas de minúsculas) e os imprimirá separados pelo caractere NULL. Isso é necessário porque os nomes de arquivos nos sistemas * nix podem conter qualquer caractere, exceto -iname e / (NULL). Assim, você pode ter arquivos com espaços, novas linhas e qualquer outro caractere estranho. Estes precisam ser tratados especialmente.
  • while IFS= read -r -d '' file; do ... done : itera a saída de find , salvando cada arquivo como $file . O IFS= define o separador do campo de entrada como nada, o que significa que podemos lidar com espaços em nomes de arquivos corretamente. O -d '' faz com que ele leia -r linhas separadas e o \ permite lidar com nomes de arquivos que contêm grep -q election "$file" .
    • -q : procura o arquivo pelo padrão. O grep suprime a saída normal e torna o && echo mv "$file" politics/ silencioso.
    • && : o grep garante que este comando só seja executado se o anterior ( %code% ) tiver sido bem-sucedido.

3. Bash.

Este script é muito similar ao da resposta do @WilhelmErasmus com a diferença de que i) ele pode pegar o conjunto de padrões e substituições da linha de comando e ii) ele também encontra arquivos em subdiretórios.

#!/usr/bin/env bash

## Exit if no arguments were given
[ -z "$1" ] && echo "At least two arguments are needed." >&2 && exit 1
## Collect the arguments
args=("$@")
## Declare the $dirs associative array
declare -A dirs

## Save the arguments given in the $dirs array.
## $# is the number of arguments given, so this
## will iterate over of them, reading two by two.
for ((i=0;i<$#;i+=2)); 
do
    ## The arguments are pairs of patterns and target directories.
    ## Set the value of this pattern to the value of the next argument,
    ## its target directory. 
    dirs[${args[$i]}]="${args[i+1]}"
done

## Ignore globs that match no files
shopt -s nullglob
## This enables ** to match subdirectories
shopt -s globstar
## Find all .html files
for file in **/*{html,htm,HTM,HTML}
do
    matched=0;
    for pat in "${!dirs[@]}"
    do
        ## Does this file match the pattern?
        ## The '-q' suppresses grep's output.
        grep -q "$pat" "$file" && 
        ## Set matched to 1 if the file matches.
        matched=1 &&
        ## If the grep succeeded, move the file
        ## to the corresponding directory
        mv "$file" "${dirs[$pat]}" && 
        ## If the move succeeded, break the loop
        ## and move to the next pattern.
        break 
    done
    ## Report files that didn't match
    [[ "$matched" -eq 0 ]] && printf "No matches for '%s'\n" "$file" >&2
done

Execute o script fornecendo os nomes dos padrões e seus destinos. Por exemplo, com os da sua pergunta:

bash move_files.sh "election" "politics" "stock market" "business" "open source" "computers" 
    
por terdon 31.03.2015 / 01:39

Tags