O awk pode usar identificadores de campo também para strings de shell (variáveis)?

3

Bem, isso aparentemente não é possível do jeito que estou tentando.

Essa abordagem alternativa para obter barra como uma string resultante funciona, no entanto:

#!/bin/bash

path1=/usr/tmp/foo/bar/baz

awk -F/ '{print $5}' <<< "$path1"

Até aí tudo bem, mas e se eu quiser fazer sem o operador <<< , bem como os notórios echo | ... pipes? Em poucas palavras, o que estou tentando fazer é passar path1 como uma variável com a diretiva -v pa="$path1" e usando o separador de campo -F/ e os identificadores de campo (por exemplo, $5 ) para analisar a variável awk - internal pa , que obteve seu valor atribuído a partir da variável shell external path1 . Isso pode ser feito "por dentro" awk também?

    
por syntaxerror 19.08.2013 / 20:22

4 respostas

7

O problema com a opção -v ou com os argumentos var=value para awk é que eles não podem ser usados para dados arbitrários desde seqüências de escape ANSI C (como \n , \b ... ) são expandidos neles.

A alternativa é usar as matrizes ARGV ou ENVIRON awk :

awk -F / 'BEGIN{$0 = ARGV[1]; print $5}' "$path1"

Ou:

export path1
awk -F / 'BEGIN{$0 = ENVIRON["path1"]; print $5}'

Ou:

path1="$path1" awk -F / 'BEGIN{$0 = ENVIRON["path1"]; print $5}'

Agora, se tudo o que você quer é dividir uma variável de shell, talvez você não precise de awk .

Em todos os shells do POSIX:

IFS=/; set -f
set -- $path1
printf '%s\n' "$5"
    
por 19.08.2013 / 21:52
3

Você pode dividir pa em uma matriz

awk -F'/' -v pa=$path1 'BEGIN{split(pa, arr, FS); print(arr[5]); exit}'
    
por 19.08.2013 / 20:31
1

Existem algumas maneiras pelas quais você pode passar variáveis de ambiente para um awk script / command:

Método 1

Isso faz com que o shell expanda a variável $path1 antes de executar o comando awk .

$ echo $path1
/usr/tmp/foo/bar/baz
$ awk -F'/' 'END{a="'$path1'"; split(a,arr,FS); print(arr[5])}' /dev/null
bar

Método # 2

Passe o env. variável como uma variável awk, a .

$ awk -F '/' 'END{split(a,arr,FS); print(arr[5])}' a=$path1 /dev/null
bar

Método 3

Explicitamente passe awk uma variável usando a opção -v .

$ awk -F'/' -v a=$path1 'END{split(a,arr,FS); print(arr[5])}' /dev/null
bar

Depuração

Você pode ativar a verbosidade do shell configurando set -x antes de executar qualquer um desses comandos para ver o que está acontecendo. Aqui está o método # 2 como um exemplo:

$ set -x
$ awk -F '/' 'END{split(a,arr,FS); print(arr[5])}' a=$path1 /dev/null
+ awk -F / 'END{split(a,arr,FS); print(arr[5])}' a=/usr/tmp/foo/bar/baz /dev/null
bar

O exemplo acima mostra set -x sendo executado seguido pela linha awk. Você pode ver que, quando executada, a variável a tem o valor de $path1 já expandido quando é executado.

Outro exemplo, este método de tempo # 1:

$ awk -F'/' 'END{a="'$path1'";split(a,arr,FS); print(arr[5])}' /dev/null
+ awk -F/ 'END{a="/usr/tmp/foo/bar/baz";split(a,arr,FS); print(arr[5])}' 
bar

Aqui você pode ver que o shell está expandindo definitivamente a variável $path1 antes de executar awk .

    
por 19.08.2013 / 21:09
0

Que tal:

basename "$(dirname "$path1")"

ou, se o seu shell suportar a substituição de processos e você precisar usar awk :

awk -F'/' '{print $5}' <(printf '%s\n' "$path1")
    
por 19.08.2013 / 20:52