Pegar os primeiros [x] caracteres de uma string em um pipe

58

Se eu tenho uma saída muito longa de um comando (linha única), mas sei que só quero os primeiros [x] (digamos 8) caracteres da saída, qual é a maneira mais fácil de conseguir isso? Não há delimitadores.

xenoterracida
fonte
related: stackoverflow.com/questions/1405611/…
Ciro Santilli escreveu:

Respostas:

82

Uma maneira é usar cut:

 command | cut -c1-8

Isso fornecerá os 8 primeiros caracteres de cada linha de saída. Como cutfaz parte do POSIX, é provável que esteja na maioria dos Unices.

Steven D
fonte
3
Observe que cut -cseleciona caracteres; cut -bou head -cseleciona bytes. Isso faz a diferença em alguns locais (na prática, ao usar UTF-8).
Gilles 'SO- stop be evil'
Você também não precisa especificar o índice inicial neste caso. Dizendo cut -c-8vai selecionar a partir de caráter 1 a 8.
Sparhawk
@Steven, cuté equivalente no Windows é?
Pacerier
Também command | dd bs=8 count=1 2>/dev/null. Não estou dizendo que é mais curto ou superior. Apenas outra alternativa.
dubiousjim
@Gilles, mas observe que nas versões atuais do GNU cut, cut -cfunciona assim cut -b(ou seja, não funciona corretamente para caracteres de vários bytes).
Stéphane Chazelas
24

Existem outras maneiras de obter apenas os 8 primeiros caracteres.

command | head -c8

command | awk '{print substr($0,1,8);exit}' 

command | sed 's/^\(........\).*/\1/;q'

E se você tiver festança

var=$(command)
echo ${var:0:8}
user1606
fonte
2
Eu acho que a seguinte formulação sed é um pouco mais fácil de ler: command | sed 's/\(.\{8\}\).*/\1/'ou se seus suportes sed-lo: command | sed -r 's/(.{8}).*/\1/'; Caso contrário, +1
Steven D
Coisas boas, mas observe que head -cconta bytes , não caracteres. Da mesma forma, entre as principais implementações do Awk, apenas o GNU awk lida com caracteres de vários bytes corretamente - o FreeBSD Awk e o Mawk não.
mklement0
2

Se você tiver um shell suficientemente avançado (por exemplo, o seguinte funcionará no Bash, não tenho certeza sobre o traço), você pode:

read -n8 -d$'\0' -r <(command)

Após a execução read ... <(command), seus caracteres estarão na variável shell REPLY. Digite help readpara aprender sobre outras opções.

Explicação: o -n8argumento para readdiz que queremos até 8 caracteres. O -d$'\0'diz lê até um nulo, em vez de uma nova linha. Dessa forma, a leitura continuará com 8 caracteres, mesmo que um dos caracteres anteriores seja uma nova linha (mas não se for nulo). Uma alternativa -n8 -d$'\0'é usar -N8, que lê exatamente 8 caracteres ou até que o stdin atinja o EOF. Nenhum delimitador é respeitado. Provavelmente isso atende melhor às suas necessidades, mas não sei de antemão quantas conchas têm uma leitura que seja honrada, -Nem vez de honrar -ne -d. Continuando com a explicação: -rdiz ignore \-escapes, de modo que, por exemplo, tratamos \\como dois caracteres, e não como um único \.

Finalmente, fazemos read ... <(command)mais do que command | read ...porque, na segunda forma, a leitura é executada em um subshell que é encerrado imediatamente, perdendo as informações que você acabou de ler.

Outra opção é fazer todo o processamento dentro do subshell. Por exemplo:

$ echo abcdefghijklm | { read -n8 -d$'\0' -r; printf "REPLY=<%s>\n" "$REPLY"; }
REPLY=<abcdefgh>
dubiousjim
fonte
11
Se você deseja apenas produzir os 8 caracteres e não precisar processá-los no shell, basta usar cut.
dubiousjim
É bom saber sobre read -n <num>; pequena ressalva: o Bash 3.x (ainda atual no SO) interpreta erroneamente <num>como uma contagem de bytes e, portanto, falha com caracteres de vários bytes; isso foi corrigido no Bash 4.x.
mklement0
Esta é uma resposta ótima e útil. Muito mais geral que os outros.
not2qubit 25/10
2

Outra solução de um liner usando expansão de parâmetro

echo ${word:0:x}

EG: word="Hello world"
echo ${word:0:3} or echo ${word::3} 
o/p: Hel


EG.2: word="Hello world"
echo ${word:1:3}
o/p: ell
Prabhat Kumar Singh
fonte
Você também pode usar uma variável com o comprimento, por exemplo: em x=8; echo ${word:0:$x}vez de codificar o número inteiro.
Cometsong 25/04
1

Isso é portátil:

a="$(command)"             # Get the output of the command.
b="????"                   # as many ? as characters are needed.
echo ${a%"${a#${b}}"}      # select that many chars from $a

Para criar uma sequência de caracteres de tamanho variável, você tem sua própria pergunta aqui .

Comunidade
fonte
0

Eu tive esse problema ao gerar manualmente arquivos de soma de verificação no repositório maven. Infelizmente, cut -csempre imprime uma nova linha no final da saída. Para suprimir que eu uso xxd:

command | xxd -l$BYTES | xxd -r

Ele gera exatamente $BYTESbytes, a menos que a commandsaída seja mais curta, exatamente essa saída.

Krzysztof Jabłoński
fonte
outro método para decolar cuta nova linha de fuga é | tr -d '\n'
inseri-