Por que é 'sed expr1 | sed expr2 'diferente de' sed-e expr1-e expr2 '

12

Eu estava dividindo a saída de id para fornecer uma lista linha por lista mais legível de grupos dos quais um usuário é membro:

id roaima | sed 's/,/\n\t/g'
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima)
    24(cdrom)
    25(floppy)
    ...
    822413650 (international (uk) location)

Eu queria separar o número do grupo de seu nome entre colchetes, então estendi a expressão assim

id roaima | sed -e 's/,/\n\t/g' -e '2,$s/(/ (/'

No entanto, isso não funcionou como inicialmente esperado. A segunda expressão pareceu não ter efeito.

Em vez disso, para obter o resultado que queria, precisei executar dois comandos sed separados, como este:

id roaima | sed -e 's/,/\n\t/g' | sed '2,$s/(/ (/'
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima)
    24 (cdrom)
    25 (floppy)
    ...
    822413650 (international (uk) location)

Por que preciso de dois comandos sed em um canal em vez de um com várias instruções? Ou se eu posso fazer isso com um sed , como eu faria isso?

O que eu gostaria particularmente é ter o espaço único entre o valor UID / GID e seu nome entre parênteses para cada item individual (incluindo o UID e GIDs na primeira linha), mas a ressalva é que nos meus dados reais eu pode ter grupos contendo colchetes em seus nomes e não quero que os nomes sejam mutilados.

    
por roaima 24.08.2017 / 17:54

3 respostas

14

sed , como awk ou cut ou perl -ne , funciona individualmente em cada linha, uma após a outra.

sed -e code1 -e code2

é realmente executado como:

while(patternspace = getline()) {
  linenumber++
  code1
  code2
} continue {print patternspace}

Se o seu código2 for 2,$ s/foo/bar/ , isso é:

if (linenumber >= 2) sub(/foo/, "bar", patternspace)

Como sua entrada tem apenas uma linha, o sub() nunca será executado.

A inserção de caracteres de nova linha no espaço padrão em code1 não aumenta o linenumber .

Em vez disso, você tem um espaço de padrão com várias linhas enquanto processa o primeiro e apenas a linha de entrada. Se você quiser fazer modificações na segunda linha e no espaço padrão multilinha, você precisa fazer algo como:

s/\(\n[^(]*\)(/ (/g

Embora aqui, é claro, você também pode fazer as duas operações de uma só vez:

id | sed 's/,\([^(]*\)(/\n\t (/g'
    
por 24.08.2017 / 18:09
5

Se você tem o GNU sed, você pode usar

id username | sed 's/(/ (/4g; s/,/\n\t/g'

que adiciona um espaço antes do quarto e parênteses subsequentes, substitui as vírgulas.

    
por 24.08.2017 / 19:17
1

O que @ stéphane-chazelas disse é verdade, mas você sempre pode adicionar o espaço primeiro e dividir em linhas depois disso:

sed -e 's:\([,=][0-9]*\): :g' -e 's:,:\n\t:g'

Ou em um único script sed (sem -e ):

sed 's:\([,=][0-9]*\): :g; s:,:\n\t:g'

Normalmente, usamos " / " como separador de pesquisas de comando, mas também aceita qualquer caractere. Por isso, às vezes é mais fácil ler usando outro caracter como " : " para evitar combinações como "% co_de" % ".

    
por 25.08.2017 / 04:08

Tags