Filtrar colunas baseando-se no valor de outra coluna

1

Eu tenho um arquivo de texto com duas colunas e mais de 3.00.000 linhas. O formato é como abaixo

Filename1.txt Num1
Filename2.txt Num2
Filename3.txt Num3

Eu quero copiar todos os nomes de arquivo para os quais o Numx correspondente é maior que 50 e menor que 200 em um arquivo diferente.

Depois de copiar esses nomes de arquivo em um arquivo diferente, quero copiar todos esses arquivos para uma pasta diferente.

Como faço isso?

    
por Innocent 17.10.2016 / 00:41

3 respostas

3

Se você quiser, pode fazer a comparação e copiar ao mesmo tempo com awk :

awk '$2>50 && $2<200 {system("cp -- "$1" /path/to/destination/")}' file.txt

Supondo que você queira copiar os arquivos para o diretório destination , altere isso para atender sua necessidade.

  • $2>50 && $2<200 faz a comparação necessária

  • se corresponder, a operação cp será executada ( {system("cp -- "$1" /path/to/destination/")} ), feita pela função system() de awk

por 17.10.2016 / 00:51
1

Vamos considerar este arquivo de teste:

$ cat file
Filename1.txt 49
Filename2.txt 72
Filename3.txt 189
Filename4.txt 203

Para selecionar apenas os arquivos para os quais a segunda coluna é maior ou igual a 50 e também menor ou igual a 200:

$ awk '$2>=50 && $2<=200 { print $1}' file
Filename2.txt
Filename3.txt

Para colocar esses nomes de arquivos em um novo arquivo em algum caminho:

awk '$2>=50 && $2<=200 { print $1}' file >/path/to/newfile

Copiando os arquivos selecionados

Supondo que os números sejam inteiros, tente:

while read fname num; do [ "$num" -ge 50 ] && [ "$num" -le 200 ] && cp -- "$fname" /some/path/ ; done <file

Ou, para aqueles que preferem o código espalhado por várias linhas:

while read fname num
do
   [ "$num" -ge 50 ] && [ "$num" -le 200 ] && cp -- "$fname" /some/path/
done <file
    
por 17.10.2016 / 00:47
0

A questão está marcada com e , então presumo que haja interesse em uma resposta que use expressões regulares. Além disso, a pergunta indica que o arquivo de dados de entrada é grande e, portanto, suponho que o desempenho seja uma consideração.

Também presumo que, dado que o arquivo de entrada contém um nome de arquivo por linha, não haverá nomes de arquivos (patológicos) que contenham caracteres de nova linha.

As outras respostas geram efetivamente um processo cp para cada arquivo. Isso causa uma redução de desempenho desnecessária. Em vez disso, podemos usar os recursos de xargs para chamar cp com tantos nomes de arquivos quanto couberem em uma linha de comando.

sed -rn 's/ (5[1-9]|[6-9].|1..)$//p' input.txt | tr '\n' '
sed -En 's/ (5[1-9]|[6-9].|1..)$//p' input.txt | tr '\n' '
sed -rn 's/ (5[1-9]|[6-9].|1..)$//p' input.txt | tr '\n' '
sed -En 's/ (5[1-9]|[6-9].|1..)$//p' input.txt | tr '\n' '%pre%' | xargs -0 -J {} cp {} /destdir
' | xargs -0 cp -t /destdir
' | xargs -0 -J {} cp {} /destdir
' | xargs -0 cp -t /destdir

O sed usa uma expressão regular para corresponder ao intervalo numérico fechado (50, 200) . Usar expressões regulares para desigualdades numéricas nem sempre é a coisa mais elegante a ser feita, mas, nesse caso, a expressão requerida é bastante direta.

Estamos assumindo que os nomes de arquivos não contêm novas linhas, mas podem conter outros caracteres inúteis, como espaços. xargs lidará com isso corretamente se receber dados tr -delimited, portanto, usaremos sed para converter todas as novas linhas em caracteres nulos.

O acima assume as versões GNU de xargs e sed . Se em vez disso você tiver versões do BSD (por exemplo, OSX), o comando será um pouco diferente:

%pre%

Esses comandos geram exatamente uma cópia de tr , xargs e cp . Haverá mais de um spawn de xargs , mas cada um copiará vários arquivos - cp tentará preencher cada linha de comando %code% para obter uma utilização eficiente. Isso deve fornecer uma melhoria de desempenho significativa em relação às outras respostas quando os dados de entrada são grandes.

    
por 17.10.2016 / 20:30