Grep linhas, mas deixe a primeira linha através de [duplicado]

23

Considere a seguinte saída de df .

Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        23G  6.1G   16G  29% /
udev             10M     0   10M   0% /dev
tmpfs           397M  420K  397M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           1.8G  904K  1.8G   1% /run/shm
/dev/sda6       890G  324G  521G  39% /home
/dev/sdb1       459G  267G  169G  62% /home/user/mnt
none            4.0K     0  4.0K   0% /sys/fs/cgroup

Como posso mostrar apenas linhas que começam com "/dev" e manter o título, mas filtram todo o resto. Eu também gostaria de não ter que recorrer ao uso de arquivos temporários ou variáveis? Nota: o cabeçalho é dependente do local, portanto você não pode pegá-lo com um regexp.

    
por Ernest A 18.12.2013 / 17:08

9 respostas

33

Eu usaria uma abordagem um pouco mais sofisticada do que simples grep :

  1. awk

    df -h | awk 'NR==1 || /^\/dev/'
    

    NR é o número da linha atual, portanto o script awk acima será impresso se essa for a primeira linha ou se a linha atual começar com /dev . E depois de postar isso, vejo que é o mesmo que a resposta do @ 1_CR. Bem ...

  2. Perl

    df -h | perl -ne 'print if (/^\/dev/ || $.==1)'
    

    A mesma ideia aqui, em Perl, a variável especial $. é o número da linha atual. Um caminho alternativo seria

    df -h | perl -pe '$_="" unless /^\/dev/ || $.==1'
    

    A opção -p imprimirá todas as linhas do arquivo de entrada. O valor da linha atual é mantido em $_ , portanto, definimos $_ como vazio, a menos que desejemos a linha atual.

  3. sed

    df -h | sed -n '1p; /^\/dev/p'
    

    O -n suprime a saída normal, portanto, nenhuma linha é impressa. O 1p significa imprimir a primeira linha e o /^\/dev/p significa imprimir qualquer linha que comece com /dev .

    Como apontado nos comentários abaixo, no caso improvável em que a localidade em seu sistema atual faz com que a linha de cabeçalho comece com /dev , o comando acima irá imprimi-lo duas vezes. Stephane Chazelas pontos a> que este não terá esse problema:

    df -h | sed  -e 1b -e '/^\/dev/!d'
    
  4. grep

    df -h | grep -E '^(/dev|File)'
    

    Isso pode não ser portátil devido a problemas de LOCALE, como você disse. No entanto, estou razoavelmente certo de que nenhum código de idioma ou df versão fornecerá um caminho na primeira linha, portanto, pesquisar por linhas que não contenham / também deve funcionar:

    df -h | grep -E '^[^/]*$|^/dev'
    
por 18.12.2013 / 17:29
15

Você vai encontrar problemas ao tentar analisar o resultado do df , no entanto, para casos simples, o seguinte pode funcionar

LC_ALL=C df -P | awk 'NR == 1 || /^\/dev/' 
    
por 18.12.2013 / 17:15
8

Isso também deve funcionar (não testado):

df | (read a; echo "$a"; grep /dev)

ou

df | (head -n 1; grep ^/dev)
    
por 19.12.2013 / 19:03
5
df -h | tee >(head -1) >(sleep 0.5;grep ^/dev) > /dev/null;sleep 1.0
    
por 18.12.2013 / 19:03
3
df | head -n 1; df | grep ^/dev
    
por 18.12.2013 / 18:33
2
df | grep -n '' | grep -E '^1:|[^:]*:/dev' | sed 's/[^:]*://'

O grep -n insere números de linha no fluxo, então nós retiramos o primeiro e as linhas de interesse via egrep, então removemos os números adicionados da saída via sed.

Você pode evitar o sed usando lookbehinds positivos (que grep pode manipular com o < href="http://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions"> mecanismo PCRE ( -P )) e -o que informam grep para imprimir apenas o padrão correspondente:

df | grep -n '' | grep -Po '(?<=^1:)(.*)|(?<=:)(/dev.*)'
    
por 19.12.2013 / 16:41
2

Em vez de filtrar a saída df, você pode filtrar sua entrada.

Antes:

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
C:/Cygwin/bin   150G   76G   74G  51% /usr/bin
C:/Cygwin/lib   150G   76G   74G  51% /usr/lib
C:/Cygwin       150G   76G   74G  51% /
C:              150G   76G   74G  51% /cygdrive/c

Depois:

$ mount | grep ^C:/Cygwin | cut -d' ' -f3 | xargs df -h
Filesystem      Size  Used Avail Use% Mounted on
C:/Cygwin/bin   150G   76G   74G  51% /usr/bin
C:/Cygwin/lib   150G   76G   74G  51% /usr/lib
C:/Cygwin       150G   76G   74G  51% /

ATUALIZAÇÃO 2014-01-24 08:03 UTC: Apenas grep para C: / Cygwin no começo de uma linha

    
por 19.12.2013 / 01:52
2

Pegue a definição de body do tipo, mas mantenha a linha de cabeçalho no topo

# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
    IFS= read -r header
    printf '%s\n' "$header"
    "$@"
}

Use-o assim

$ df -h | body grep ^/dev
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        23G  6.1G   16G  29% /
/dev/sda6       890G  324G  521G  39% /home
/dev/sdb1       459G  267G  169G  62% /home/user/mnt
    
por 02.02.2014 / 20:52
-3
df -h | egrep -e Filesystem -e "/dev" -v
    
por 20.12.2013 / 20:17