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"