Obter o último campo usando substr do awk

99

Estou tentando usar awkpara obter o nome de um arquivo, dado o caminho absoluto para o arquivo.
Por exemplo, ao receber o caminho de entrada /home/parent/child/filenameque gostaria de obter filename , tentei:

awk -F "/" '{print $5}' input

que funciona perfeitamente.
No entanto, estou codificando, o $5que seria incorreto se minha entrada tivesse a seguinte estrutura:

/home/parent/child1/child2/filename

Portanto, uma solução genérica exige sempre pegar o último campo (que será o nome do arquivo).

Existe uma maneira simples de fazer isso com a função substr do awk?

Mari
fonte
2
como alguém apontou, usar basenameé a forma oficial de fazer isso, usar awkpara isso não é bom para dizer o mínimo. : D
Kashyap

Respostas:

206

Use o fato de que awkdivide as linhas em campos com base em um separador de campo, que você pode definir. Portanto, definindo o separador de campo para /você pode dizer:

awk -F "/" '{print $NF}' input

como NFse refere ao número de campos do registro atual, impressão$NF significa imprimir o último.

Então, dado um arquivo como este:

/home/parent/child1/child2/child3/filename
/home/parent/child1/child2/filename
/home/parent/child1/filename

Este seria o resultado:

$ awk -F"/" '{print $NF}' file
filename
filename
filename
fedorqui 'então pare de prejudicar'
fonte
3
Funciona perfeitamente. Não pensei na variável $ NF. Obrigado pela sua resposta imediata simples e eficaz.
Mari
6
Para o penúltimo, use $(NF-1).
Itachi
1
Estava escrevendo um script para trabalhar com alguns comandos do docker e isso funcionou. Obrigado!
Harlin de
30

Nesse caso, é melhor usar em basenamevez de awk:

 $ basename /home/parent/child1/child2/filename
 filename
piokuc
fonte
4
@Mari FYI dirname faz o oposto e remove o arquivo, não o caminho.
Chris Seymour
5

Outra opção é usar a bash substituição de parâmetro .

$ foo="/home/parent/child/filename"
$ echo ${foo##*/}
filename
$ foo="/home/parent/child/child2/filename"
$ echo ${foo##*/}
filename
Devnull
fonte
5

Se você está aberto a uma solução Perl, aqui está uma semelhante à solução awk de Fedorqui:

perl -F/ -lane 'print $F[-1]' input

-F/especifica /como o separador de campo
$F[-1]é o último elemento na @Fmatriz de divisão automática

Chris Koknat
fonte
1
Obrigado. Isso me ajudou a conseguir o último, mas um campo. perl -F "/" -lane 'print $ F [-2]' input
riderchap
isso funcionou para mim ao receber de entrada canalizada. Esqueci totalmente o perl.
Christopher
3

Deve ser um comentário para a resposta do nome de base, mas não tenho motivos suficientes.

Se você não usar aspas duplas, basenamenão funcionará com o caminho onde há caractere de espaço:

$ basename /home/foo/bar foo/bar.png
bar

ok com aspas ""

$ basename "/home/foo/bar foo/bar.png"
bar.png

exemplo de arquivo

$ cat a
/home/parent/child 1/child 2/child 3/filename1
/home/parent/child 1/child2/filename2
/home/parent/child1/filename3

$ while read b ; do basename "$b" ; done < a
filename1
filename2
filename3
Pierre-Damien
fonte
3

Eu sei que estou cerca de 3 anos atrasado nisso, mas .... você deve considerar a expansão dos parâmetros, é embutida e mais rápida.

se sua entrada estiver em uma var, digamos, $ var1, basta fazer ${var1##*/}. Olhe abaixo

$ var1='/home/parent/child1/filename'
$ echo ${var1##*/}
filename
$ var1='/home/parent/child1/child2/filename'
$ echo ${var1##*/}
filename
$ var1='/home/parent/child1/child2/child3/filename'
$ echo ${var1##*/}
filename
Adriano_Pinaffo
fonte
2

Tipo 5 anos atrasado, eu sei, obrigado por todas as propostas, eu costumava fazer isso da seguinte maneira:

$ echo /home/parent/child1/child2/filename | rev | cut -d '/' -f1 | rev
filename

Fico feliz em notar que existem maneiras melhores

Nicko Glayre
fonte
-1

Você também pode usar:

    sed -n 's/.*\/\([^\/]\{1,\}\)$/\1/p'

ou

    sed -n 's/.*\/\([^\/]*\)$/\1/p'
SARATH
fonte
1
Neste ponto, ninguém votou a favor desta resposta, provavelmente porque é comparativamente feia :)
Josip Rodin