Com ferramentas GNU (shell GNU ou outro shell com suporte para ksh substituição de processo ( <(...)
), GNU xargs
ou compatível como o FreeBSD (para -a
, -r
, -0
), GNU mv
para -t
, GNU awk
para nextfile
(também suportado por algumas outras implementações; ele será ignorado, mas menos eficiente quando não suportado)):
xargs -r0a <(
find dir -type f -exec awk 'FNR == 2 {
if (substr($0, 8, 2) == "EL" && substr($0, 42, 4) == "2017")
printf "%s{
find dir -type f -exec awk -v q="'" '
function quote_for_xargs(s) {
gsub(q, q "\" q q, s)
gsub("\n", q "\\n" q, s)
return q s q
}
FNR == 2 {
if (substr($0, 8, 2) == "EL" && substr($0, 42, 4) == "2017")
print quote_for_xargs(FILENAME)
nextfile
}' {} + | xargs sh -c '
[ "$#" -eq 0 ] || exec echo mv -i "$@" /somewhere <&3 3<&-' sh
} 3<&0
", FILENAME
nextfile}' {} +) echo mv -it /somewhere
(remova echo
se estiver feliz)
Em sistemas não-GNU, você pode alterá-lo para:
xargs -r0a <(
find dir -type f -exec awk 'FNR == 2 {
if (substr($0, 8, 2) == "EL" && substr($0, 42, 4) == "2017")
printf "%s{
find dir -type f -exec awk -v q="'" '
function quote_for_xargs(s) {
gsub(q, q "\" q q, s)
gsub("\n", q "\\n" q, s)
return q s q
}
FNR == 2 {
if (substr($0, 8, 2) == "EL" && substr($0, 42, 4) == "2017")
print quote_for_xargs(FILENAME)
nextfile
}' {} + | xargs sh -c '
[ "$#" -eq 0 ] || exec echo mv -i "$@" /somewhere <&3 3<&-' sh
} 3<&0
", FILENAME
nextfile}' {} +) echo mv -it /somewhere
(remova echo
se estiver feliz).
Isso tem find
call awk
para cada arquivo de texto. Em awk
, para a segunda linha de cada arquivo ( FNR==2
), se as condições forem atendidas, imprimir o nome do arquivo é um formato adequado para xargs
(a entrada xargs é tratada como uma lista de palavras separadas por espaços em branco ou novas linhas e onde aspas simples e duplas e barras invertidas podem ser usadas para escapar dos separadores ou uns dos outros). Por exemplo, um arquivo chamado ./That's tough.log
seria exibido como './That'\''s tough.log'
.
xargs
usa essa entrada para passar o maior número de argumentos possível para sh
. Precisamos do wrapper sh
porque o diretório de destino deve ser o último argumento. Nós queremos o -i
porque desde que os arquivos acabam no mesmo diretório, há espaço para os dados serem perdidos se dois arquivos com o mesmo nome em diretórios diferentes estiverem sendo movidos. Precisamos que o stdin de mv
(para o prompt -i
) seja não o pipe de find
, daí o uso de um fd temporário 3 para encaminhar o stdin externo para sh
de sh
para definir o valor de mv
nessa.