Somente 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 sequência de caracteres em um "(.)" Para corresponder e capturar regex com =~
, e apenas gerar as expressões capturadas da BASH_REMATCH[]
matriz, agrupadas conforme necessário. Os espaços à esquerda / à direita / intermediários são preservados, remova as aspas "${BASH_REMATCH[@]:1}"
para omiti-las.
Aqui está envolvido 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 sequência de formatação de acordo.
Um espaço à direita é adicionado, 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}"
A primeira printf
imprime (até) os 4 primeiros caracteres, a segunda imprime condicionalmente todo o restante (se houver) com um espaço à esquerda para separar os grupos. O teste é para 5 elementos e não 4 para dar conta do elemento zeroth.
Notas:
- shell
printf
s' %c
pode ser usado em vez de %s
, %c
(talvez) faz a intenção mais clara, mas não é multi-byte caráter. Se a sua versão do bash for capaz, as opções acima são seguras para caracteres de vários bytes.
- O shell
printf
reutiliza sua string de formatação até ficar sem argumentos, portanto, apenas devolve 4 argumentos por vez e lida com os argumentos à direita (portanto, não são necessários casos extremos, ao contrário de algumas das outras respostas aqui que estão indiscutivelmente erradas)
BASH_REMATCH[0]
é a sequência correspondente completa, portanto, apenas a saída começa no índice 1
- em
printf -v myvar ...
vez disso, use para armazenar em uma variável myvar
(sujeita ao comportamento usual de leitura / loop / subcamação)
- adicione
printf "\n"
se necessário
Você pode fazer o trabalho acima zsh
se usar a matriz em match[]
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.
sed
eu tentei primeiro eu poderia me chutar.