Bytes simples
Se a cadeia contiver apenas bytes ASCII e nenhuma nova linha, você poderá usar cut
.
O comando cut
poderia trabalhar com apenas bytes .
$ echo "ajgjkggéóskmæßðasgbmdéóskmæßðushghsvéóskmæßð" | cut -b 1-5
ajgjk
Mas isso falhará assim que a string de corte contiver caracteres de múltiplos bytes:
$ echo "ajgjkggéóskmæßðasgbmdéóskmæßðushghsvéóskmæßð" | cut -b 7-12
géós
Existem 6 bytes (7,8,9,10,11 e 12), mas esses não são 6 caracteres.
E o corte também quebra se houver novas linhas na string.
Caracteres
Para trabalhar com caracteres "multi-byte", precisamos de uma ferramenta que entenda esses caracteres de multibyte, ambos sed
e awk
do.
O comando sed
pode extrair caracteres de uma string:
$ s=5;l=3;echo "ajgjkggéóskm" | sed -E 's/^.{'"$s"'}(.{'"$l"'}).*//'
ggé
Mas a opção -E é uma extensão GNU, por isso precisamos mudar a linha para torná-la compatível com um POSIX sed (somente BRE regex):
$ s=5;l=3;echo "ajgjkggéóskm" | sed 's/^.\{'"$s"'\}\(.\{'"$l"'\}\).*//'
ggé
Se a string não contiver novas linhas. Como sed quebra a entrada é linhas em cada caractere de nova linha.
Isso quebra assim que houver novas linhas:
$ s=1;l=3;echo $'ajéw\nóskmæß\nðqwee' | sed 's/^.\{'"$s"'\}\(.\{'"$l"'\}\).*//'
jéw
skm
qwe
A saída é de fato 3 caracteres começando com a primeira (1), mas para cada linha.
Chars e novas linhas.
A única outra ferramenta disponível é o awk. Que faz ter uma especificação POSIX .
Usando as Funções de string disponíveis no AWK :
$ s=6;l=4;echo "ajgjkggéóskm" | awk -v m="$s" -v n="$l" '{print substr($0,m,n)}'
ggéó
Mas isso também quebra novas linhas:
$ s=1;l=3;echo $'ajéw\nóskmæß\nðqwee' | awk -v m="$s" -v n="$l" '{print substr($0,m,n)}'
ajé
ósk
ðqw
No entanto, podemos especificar um caractere que não deve estar em uso na string, como o RS (separador de registro): o byte nulo (\ 0). Isso proíbe as strings que contêm NULs (\ 0), um problema muito raro.
Por favor note que estou não falando sobre a string vazia: ''
, pois isso fará com que o awk use uma "linha vazia" como separador de registro.
Para fazer isso, usarei uma capacidade de bash (nem todas as shells poderiam fazer isso) de escrever um zero byte como este: $'main "$@"
'
. Para outras camadas, a solução deve ser diferente.
Se o AWK estiver configurado com esse RS, ele receberá toda a entrada como um registro.
$ s=1;l=3;echo $'ajéw\nóskmæß\nðqwee' |
awk -v RS=$'#!/bin/bash
main(){
while [ $# -gt 0 ]; do
s=${1//[^0-9]/}; s="$((${s?Missing start of text.}+0))"
l=${2//[^0-9]/}; s="$((${l?Missing start of text.}+0))"
echo "from $s read $l characters"
shift 2
readchars "$s" "$l"
done
}
readchars(){
awk -v RS=$'$ ./script.sh 35 12
from 35 read 12 characters
mæßð
aéóskmæ
' -v sstr="$1" -v lstr="$2" '
{printf("%s\n",substr($0,sstr,lstr))}
' <<-\_safe_place_for_string_
aéóskmæßðasgbmdéóskmæßðushghsvéóskmæßð
aéóskmæßðasgbmdéóskmæßðushghsvéóskmæßð
aéóskmæßðasgbmdéóskmæßðushghsvéóskmæßð
_safe_place_for_string_
}
main "$@"
' -v m="$s" -v n="$l" '{print substr($0,m,n)}'
ajé
Não há mais interferência de nova linha. Bem, precisamos usar printf para evitar alguns problemas com a impressão de novas linhas. Com isso, poderíamos construir um script.
Algumas notas no script, como não é tão normal:
- O script inicia a execução na última linha:
_safe_place_for_string_
. Isso garante que todo o script tenha sido lido por bash e que ambas as funções definidas tenham sido analisadas.
- A (s) linha (s) entre os dois
_safe_place_for_string_
deve ser preenchida com qualquer texto que você precise incluir no arquivo.
- O último
}
deve estar no início de uma linha, não ter texto adicional depois dele (nem mesmo espaços) e começar no início da linha (ou depois de um caractere de tabulação).
- Depois disso, deve haver o fechamento da função
main "$@"
e o início da execução: \n
O script:
$ echo "ajgjkggéóskmæßðasgbmdéóskmæßðushghsvéóskmæßð" | cut -b 1-5
ajgjk
Chame o script como:
$ echo "ajgjkggéóskmæßðasgbmdéóskmæßðushghsvéóskmæßð" | cut -b 7-12
géós
Note que a primeira "nova linha" vem de dentro da string. A última "nova linha" foi adicionada pelo ./script.sh 35 12 17 12
no printf, você pode removê-la, se necessário.
Ou até mesmo como while
, o %code% interno processará as chamadas repetidas.
Lembre-se de colocar seu texto no script para obter a saída esperada.