awk + paste para limpeza do PATH?

5

Eu vi esse código em .cshrc arquivos init em algumas máquinas. Eu passei por alguns tutoriais do awk ao tentar entender como funciona, mas ainda não consigo decifrá-lo.

setenv PATH 'echo $PATH | awk 'NF&&\!x[$0]++' RS='[:|\n]' | paste -sd:'

O que isso faz?

    
por Josh 18.05.2013 / 23:28

2 respostas

6

Não funciona para mim com as barras invertidas, mas posso explicar isso para você:

echo "$PATH" | awk 'NF && !x[$0]++' RS='[:|\n]'

O separador de registro ( RS ) é definido como um dos caracteres ":", "|" e nova linha. $PATH é geralmente apenas uma linha com elementos separados por ":". Isso faz o awk se comportar como se os caminhos não fossem separados por ":", mas cada um em sua própria linha.

NF significa que linhas vazias ( NF == 0 ) são ignoradas. x é uma matriz associativa com os caminhos como subscrito. !x[$0]++ significa que a "linha" é ignorada se x[$0] for maior que 0. O resultado é que cada linha é enviada apenas uma vez. Durante a primeira execução, x[$0] é aumentado para que, nas execuções a seguir, !x[$0] seja falso.

Este exemplo mostra a frequência de todos os elementos após a última linha ter sido processada:

echo "a:b:a:c:a:b" |
  awk 'NF && !x[$0]++;END {for (var in x) print var ": " x[var]}' RS='[:|\n]'
a
b
c
a: 3
b: 2
c: 1
    
por 19.05.2013 / 00:03
2

Como descrito por Hauke , a intenção aqui é apenas ter elementos únicos na variável $PATH .

No entanto, este não é um script awk portátil, RS é frequentemente restrito a apenas um único caractere e não uma expressão regular. Uma alternativa mais portátil seria algo assim:

setenv PATH 'printf "%s" "$PATH" | awk '{ sub("/$","") }; x[$0]++ < 1' RS=: | paste -s -d : -'

Testado em tcsh com gawk e nawk.

Algumas coisas a serem observadas:

  • a nova linha estranha é evitada usando printf .
  • o ! , que significa expansão do histórico para tcsh, pode ser substituído verificando se o valor é menor que 1.
  • Os separadores de caminho de terminação
  • são removidos com sub() .
por 19.05.2013 / 13:06