Obter um elemento da cadeia de caminho usando o bash

9

Eu tenho um arquivo ASCII contendo caminhos de arquivo que li executando:

while read p; do echo $p; done < filelist.txt

O arquivo contém caminhos de arquivo com o seguinte padrão:

./first/example1/path
./second/example1/path
./third/example2/path

Como posso obter uma parte específica da string do caminho (de /para /), por exemplo, preciso obter uma saída que imprima:

first
second
third

e também

example1
example1
example2

Tenho certeza de que existe uma maneira de fazer isso usando expressões regulares e sed, mas não estou familiarizado com isso.

mcExchange
fonte

Respostas:

17

Use cut:

$ cat filelist.txt
./first/example1/path
./second/example1/path
./third/example2/path

$ cut -d/ -f2 filelist.txt 
first
second
third

$ cut -d/ -f3 filelist.txt 
example1
example1
example2

A -d/define o delimitador de coluna para /e os -f2seleciona a 2ª coluna.

Obviamente, você também pode usar variáveis ​​Bash em vez de um nome de arquivo ou canalizar dados no cutcomando:

cut -d/ -f3 $MyVariable
echo ./another/example/path | cut -d/ -f3
Byte Commander
fonte
Usar | cut -d/ -f3 um cachimbo fez o truque. Obrigado! Este é o comando completo agora: while read p; do echo $p; done < filelist.txt | cut -d/ -f3
mcExchange 24/16
3
@mcExchange Não há razão para usar esse loop while. É muito mais simples de apenas fazer cut -d/ -f3 filelist.txt
Monty mais dura
1
Além disso, evitar o tempo evita problemas de cotação e não falhará com novas linhas nos nomes dos arquivos.
Volker Siegel
10

Você poderia fazê-lo diretamente em seu readcomando, usando a IFSvariável eg

$ while IFS=/ read -r p1 p2 p3 r; do echo "$p2"; done < filelist.txt 
first
second
third
chave de aço
fonte
5

Você pode usar awk

pilot6@Pilot6:~$ cat filelist.txt
./first/example1/path
./second/example1/path
./third/example2/path

pilot6@Pilot6:~$ awk -F "/" '{print $2}' filelist.txt
first
second
third

pilot6@Pilot6:~$ awk -F "/" '{print $3}' filelist.txt
example1
example1
example2
Pilot6
fonte
3

Se quisermos qualquer elemento do caminho, é melhor usar algo que possa dividir uma sequência em campos, como , ,ou . Contudo, também pode fazer o trabalho com substituição de parâmetro, usando substituição de padrão e jogando tudo em uma matriz.

$> echo ${FILE//\//\ }                                                         
sys class backlight intel_backlight brightness
$> ARRAY=( ${FILE//\//" " } )                                                  
$> echo ${ARRAY[2]}
backlight

$> FILE="./dir1/dir2/file.txt"                                                 
$> ARRAY=( ${FILE//\/" "} )
$> echo ${ARRAY[@]}                                                            
. dir1 dir2 file.txt
$> echo ${ARRAY[1]}
dir1

Agora, temos uma variedade de itens fora do caminho. Observe que, se o caminho contiver espaços, poderá envolver a alteração do separador de campo interno IFS.

Sergiy Kolodyazhnyy
fonte
1

Bash e cutsão o caminho a percorrer, no entanto, uma alternativa usando Perl:

perl -F/ -lane 'print(@F[1])' filelist.txt

para o segundo /campo delimitado e

perl -F/ -lane 'print(@F[2])' filelist.txt

para o terceiro /campo delimitado.

  • -l: ativa o processamento automático de final de linha. Tem dois efeitos separados. Primeiro, ele chomps $ / (o separador de registro de entrada) automaticamente quando usado com -n ou -p. Segundo, ele atribui $ \ (o separador de registros de saída) para ter o valor de octnum, para que quaisquer instruções de impressão tenham esse separador adicionado novamente. Se o octnum for omitido, configure $ \ para o valor atual de $ /.
  • -a: ativa o modo de divisão automática quando usado com -n ou -p. Um comando de divisão implícito para a matriz @F é feito como a primeira coisa dentro do loop while implícito produzido pelo -n ou -p.
  • -n: faz com que o Perl assuma o seguinte loop em torno do seu programa, o que faz com que ele itere sobre os argumentos do nome do arquivo, como sed -n ou awk:

    LINE:
      while (<>) {
          ...             # your program goes here
      }
  • -e: pode ser usado para inserir uma linha de programa;

  • print(@F[N]): imprime o enésimo campo.
% cat filelist.txt 
./first/example1/path
./second/example1/path
./third/example2/path
% perl -F/ -lane 'print(@F[1])' filelist.txt
first
second
third
% perl -F/ -lane 'print(@F[2])' filelist.txt
example1
example1
example2
kos
fonte