Use o sed da seguinte forma:
$ echo "foobarbazblargblurg" | sed 's/.\{4\}/& /g'
foob arba zbla rgbl urg
Eu tenho uma longa linha que eu quero inserir um espaço a cada 4 caracteres, em uma única linha solitária de texto sólido para facilitar a leitura, qual é a maneira mais simples de fazer isso? Eu também deveria poder inserir a linha de um cano. por exemplo,
echo "foobarbazblargblurg" | <some command here>
dá
foob arba zbla rgbl urg
Você pode usar o seguinte exemplo simples:
$ echo "foobarbazblargblurg" | fold -w4 | paste -sd' ' -
foob arba zbla rgbl
Vou responder inserindo apenas espaços conforme necessário, para que um espaço apareça pelo menos a cada 4 caracteres em uma linha; Não tenho certeza de que maneira você quer lidar com este caso. Por exemplo, dada a entrada "aa bbccdd", você obteria a saída "aa bbcc dd" em vez de "aa b bccd d".
Estou usando o Perl para lookahead, mas não estou muito familiarizado com o Perl em geral, portanto, pode haver ajustes necessários:
$ echo "foobarbazblargblurg" | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
foob arba zbla rgbl urg
$ echo 'aa bbccdd' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
aa bbcc dd
# not 'aa b bccd d'!
$ echo 'some input' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
some inpu t
# not 'some inp ut'!
$ echo $'aabb\nc cddee' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g' |
> while read; do echo "${REPLY}x"; done
aabbx
c cdde ex
# no spaces added at the end of the first line (while loop to add to the end of
# the line and show this)
Aqui está o exemplo usando grep
e xargs
:
$ echo "foobarbazblargblurg" | grep -o .... | xargs
foob arba zbla rgbl
Apenas no bash, sem comandos externos:
str="foobarbazblargblurg"
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
ou como uma versão de tubo de uma linha:
echo foobarbazblargblurg |
{ IFS= read -r str; [[ $str =~ ${str//?/(.)} ]]; \
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"; }
A maneira como isso funciona é converter cada caractere da string em um "(.)" para correspondência de regex e captura com =~
, em seguida, apenas exibe as expressões capturadas de BASH_REMATCH[]
array, agrupadas conforme necessário. Os espaços iniciais / finais / intermediários são preservados, remova as aspas em torno de "${BASH_REMATCH[@]:1}"
para omití-las.
Aqui está empacotado em uma função, esta processará seus argumentos ou lerá stdin se não houver argumentos:
function fmt4() {
while IFS= read -r str; do
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
done < <( (( $# )) && printf '%s\n' "$@" || printf '%s\n' $(< /dev/stdin) )
}
$ echo foobarbazblargblurg | fmt4
foob arba zbla rgbl urg
Você pode facilmente parametrizar a contagem para ajustar a string de formato de acordo.
É adicionado um espaço à direita, use dois printf
s em vez de um, se isso for um problema:
printf "%s%s%s%s" "${BASH_REMATCH[@]:1:4}"
(( ${#BASH_REMATCH[@]} > 5 )) && printf " %s%s%s%s" "${BASH_REMATCH[@]:5}"
O primeiro printf
imprime (até) os primeiros 4 caracteres, o segundo condicionalmente imprime todo o resto (se houver) com um espaço à esquerda para separar os grupos. O teste é para 5 elementos, e não 4, para o elemento zeroth.
Notas:
printf
do %c
do shell pode ser usado em vez de %s
, %c
(talvez) torna a intenção mais clara, mas não é um caractere de multibyte seguro. Se a sua versão do bash é capaz, o acima é todo o caráter multi-byte seguro. printf
reutiliza sua string de formato até ficar sem argumentos, por isso apenas devolve até 4 argumentos por vez e manipula os argumentos finais (portanto, nenhum caso de borda é necessário, diferente de outras respostas aqui que são indiscutivelmente errado) BASH_REMATCH[0]
é toda a string correspondida, portanto, apenas a saída a partir do índice 1 printf -v myvar ...
para armazenar em uma variável myvar
(sujeito ao comportamento usual de loop de leitura / subshell) printf "\n"
se necessário Você pode fazer o trabalho acima em zsh
se usar a matriz match[]
em vez de BASH_REMATCH[]
e subtrair 1 de todos os índices, pois zsh
não mantém um elemento 0 com a correspondência inteira.
Com zsh
apenas:
str=foobarbazblargblurg
set -o extendedglob
printf '%s\n' ${str//(#m)????/$MATCH }
Ou
printf '%s%s%s%s ' ${(s::)str}
com ksh93
apenas:
printf '%s\n' "${str//????/out=
while true; do
case $str in
(?????*)
new_str=${str#????}
out=$out${str%"$new_str"}' '
str=$new_str
;;
(*)
out=$out$str
break
esac
done
printf '%s\n' "$out"
}"
Com qualquer shell POSIX somente (evitando também o espaço à direita se o tamanho da entrada for um múltiplo de 4):
set -o rematchpcre
str=$'Ste\u301phane' out=
while [[ $str =~ '(\X{4})(.+)' ]] {
out+="$match[1] " str=$match[2]
}
out+=$str
printf '%s\n' $out
Agora, isso é para caracteres . Se você quisesse fazer isso em clusters de grapheme (por exemplo, para quebrar Stéphane
, escrito como $'Ste\u0301phane'
, como Stép hane
e não Ste phan e
), com zsh
:
str=$'Ste\u301phane' out=
while
start=${ printf %L.4s. "$str"; }
start=${start%.}
[ "$start" != "$str" ]
do
out+="$start " str=${str#"$start"}
done
out+=$str
printf '%s\n' "$out"
Com o ksh93, você também pode dividir a largura de exibição, o que funcionaria para o Stéphane
acima, mas também pode ajudar quando outros tipos de caracteres de largura zero ou de largura dupla estiverem envolvidos:
str=foobarbazblargblurg
set -o extendedglob
printf '%s\n' ${str//(#m)????/$MATCH }
Eu fiz isso usando python
Primeiro eu estou lendo o arquivo, então estou dividindo por 4 caracteres e adicionando espaço
#!/usr/bin/python
import re
b=re.compile(r'[a-z]{4}')
p=open('/root/l.txt','r')
i=p.readlines()
for j in i:
m=re.findall(b,j)
print " " .join (m) + " "
/root/l.txt == > Consiste no conteúdo que você deu no exemplo
saída
foob arba zbla rgbl