Eu sei que o cut
comando pode imprimir os primeiros n
caracteres de uma string, mas como selecionar os últimos n
caracteres?
Se eu tiver uma sequência com um número variável de caracteres, como posso imprimir apenas os últimos três caracteres da sequência. por exemplo.
saída "ilimitada" necessária é "ted" A saída "987654" necessária é "654" A saída "123456789" necessária é "789"
text-processing
cut
odisseia
fonte
fonte
grep -o '.\{3\}$'
echo "unlimited" | python -c "print raw_input()[-3:]"
"echo unlimited" | java -jar EnterpriseWordTrimmer.jar
, mas não acho que seja realmente necessário trazer uma linguagem mais pesada para a manipulação de personagens.java -server -Xms300M -Xmx3G -XX:+UseParallelGC -cp /path/to/all/the/jars/ -Dinput.interactive=false -Dinput.pipe=true -Dconfig.file=/path/to/config/last-three-letters.cfg -jar ...
grep -o -P '.{0,3}$'
imprimirá os últimos 3 caracteres, mesmo que a linha tenha menos de 3 caracteres.-P
evita ter que escapar do aparelho.Mantendo-o simples - cauda
Não devemos precisar de uma expressão regular, ou mais de um processo, apenas para contar caracteres.
O comando
tail
, geralmente usado para mostrar as últimas linhas de um arquivo, possui uma opção-c
(--bytes
), que parece ser a ferramenta certa para isso:(Quando você está em um shell, faz sentido usar um método como na resposta do mikeserv, porque economiza o início do processo
tail
.)Caracteres Unicode reais?
Agora, você pede os três últimos caracteres ; Não é isso que esta resposta lhe dá: ela gera os últimos três bytes !
Contanto que cada caractere tenha um byte,
tail -c
apenas funciona. Então, ele pode ser usado se o conjunto de caracteres éASCII
,ISO 8859-1
ou uma variante.Se você tiver entrada Unicode, como no
UTF-8
formato comum , o resultado está errado:Neste exemplo, usando
UTF-8
, os caracteres gregos alfa, beta e gama têm dois bytes de comprimento:A opção
-m
pode pelo menos contar os caracteres unicode reais:Ok, então os últimos 6 bytes nos fornecerão os últimos 3 caracteres:
Portanto,
tail
ele não suporta manipulação de caracteres gerais e nem tenta (veja abaixo): Ele lida com linhas de tamanho variável, mas sem caracteres de tamanho variável.Vamos colocar desta maneira:
tail
é ideal para a estrutura do problema resolver, mas errado para o tipo de dados.GNU coreutils
Olhando mais, verifica-se que te coreutils GNU, a coleção de ferramentas básicas, como
sed
,ls
,tail
ecut
, ainda não está totalmente internacionalizado. O que é principalmente sobre o suporte ao Unicode.Por exemplo,
cut
seria um bom candidato para usar em vez de cauda aqui para suporte ao personagem; Possui opções para trabalhar em bytes ou caracteres,-c
(--bytes
) e-m
(--chars
);Somente isso
-m
/--chars
na versãocut (GNU coreutils) 8.21
2013não foi implementado!
De
info cut
:Veja também esta resposta para Não é possível usar `cut -c` (` --characters`) com UTF-8? .
fonte
cut
solução e a de Glenn Jackman não parecem.tail
deve lidar com bytes, e não com caracteres. Uma vez fiz um patch para adicionar uma nova opção de também selecionar caracteres, mas eu acredito que nunca chegou fundiu: - /tail -c3 -n10 /var/log/syslog
tail -c3 -n10 /var/log/syslog
pede as últimas 10 linhas, e isso funciona para mim. Você usa a opção-c3
e, depois disso, a opção conflitante-n10
. A opção posterior tem prioridade.Se o seu texto estiver em uma variável de shell chamada
STRING
, você poderá fazer isso em abash
,zsh
oumksh
shell:Ou
que também tem o benefício de trabalhar com o ksh93 de onde vem essa sintaxe.
O ponto é que ele
:
precisa ser separado do-
caso contrário, ele se torna o${var:-default}
operador do shell Bourne.A sintaxe equivalente nos shells
zsh
ouyash
é:fonte
${STRING:(-3):3}
(especificando o campo de comprimento ),${STRING: -3}
(com um espaço entre o:
e o-
), ou${STRING: -3:3}
.3
é um tanto discutível, pois está solicitando "os três caracteres do terceiro do último caractere, inclusive", que é uma operação idêntica em termos práticos a "Todos os caracteres do terceiro ao último" , inclusive ".Usando
awk
:fonte
Se a sequência estiver em uma variável, você poderá:
Isso retira os três últimos caracteres do valor de
$var
like:... e depois tira da cabeça de
$var
tudo, mas o que foi simplesmente despido como:Este método tem suas vantagens e desvantagens. Pelo lado positivo, é totalmente portátil para POSIX e deve funcionar em qualquer shell moderno. Além disso, se
$var
não contiver pelo menos três caracteres, nada\n
será impresso, mas o ewline à direita . Então, novamente, se você quiser que seja impresso nesse caso, precisará de uma etapa adicional como:Dessa maneira,
$last3
somente estará vazio se$var
contiver 3 ou menos bytes. E$var
só é substituído por$last3
se$last3
está vazio ouunset
- e sabemos que não éunset
porque apenas o definimos.fonte
printf
strings de formato?${VARNAME:(-3)}
(presumirbash
)?bash
quanto em qualquer outro shell que reivindica a comapibilidade do POSIX.csh
está entre as conchas modernas compatíveis com POSIX que mencionei aqui, infelizmente. A especificação do POSIX-shell é modelada após , que se modelou após uma combinação de ambos e os shells tradicionais do estilo Bourne. incorporou a excelente funcionalidade de controle de tarefas e o redirecionamento de E / S dos antigos estilos Bourne. Ele também adicionou algumas coisas - como os conceitos de manipulação de string que demonstro acima. Provavelmente, isso não funcionará em nenhum tradicional , pelo que sei, lamento dizer.ksh
csh
ksh
csh
csh
Você pode fazer isso, mas isso é um pouco ... excessivo:
fonte
A solução à prova de balas para cordas utf-8:
Ou use:
para impedir o tratamento incorreto dos dados.
Exemplo:
Produz algo como isto:
Não depende das configurações de localidade (ou seja, funciona com
LC_ALL=C
).Bash
,sed
,grep
,awk
,rev
Requerem algo como isto:LC_ALL=en_US.UTF-8
Solução comum:
Você pode detectar a codificação com uchardet . Veja também projetos relacionados .
Você pode decodificar / codificar com Encode no Perl, codecs no Python 2.7
Exemplo :
Extraia os últimos três caracteres da string utf-16le e converta esses caracteres em utf-8
Veja também: perlunitut , HOWTO Unicode em Python 2
fonte
echo
é a sua fonte à prova de balas?decode/encode
é minha fonte à prova de balas. Limpei minha resposta.LC_ALL=C
porque é uma configuração muito "burra", mas pode quebrar quando você tenta passar uma string UTF-8 para SHIFT-5 ou uma string SHIFT-5 para KOI8, etc.perl -CAO -e 'print substr($ARGV[0], -3)'
funcione bem.A
espera-se que os elementos @ARGV sejam cadeias de caracteres codificadas em UTF-8,O
STDOUT estará em UTF-8.utf8_str
Que tal usar "expr" ou "rev"?
Uma resposta semelhante à fornecida pelo @ G-Man :
expr "$yourstring" : '.*\(...\)$'
tem a mesma desvantagem que a solução grep.Um truque bem conhecido é combinar "cut" com "rev":
echo "$yourstring" | rev | cut -n 1-3 | rev
fonte
rev
solução se parece muito com a de glenn jackmanObtenha o tamanho da string com:
Em seguida, obtenha a substring do último n caractere:
Por exemplo:
daria:
fonte
tail -n 1 revisions.log | awk '{substr de impressão ($ 0, 0, comprimento ($ 0) - (comprimento ($ 0) -13)))}'
Se você deseja imprimir os primeiros treze caracteres desde o início
fonte
printf não funcionará se a string tiver espaços.
Abaixo do código para string com espaço
fonte
printf
não funcionar, você está fazendo algo muito errado.printf $str
(em vez deprintf "$str"
ouprintf '%s' "$str"
). E sim,printf $str
está muito errado. (echo -n $str
não é muito melhor.)