Como fazer o loop de uma função de leitura no Bash Script?

1

Eu precisava remover espaços e letras maiúsculas para várias seqüências de texto, como:

"My Name is Mauro" -> "my_name_is_mauro"

Então eu criei este script bash: lowercase_underscore.sh (chame o mesmo para testes). Existe outra maneira de conseguir isso com um loop?

#!/bin/bash
echo "Please enter a word:
(leave blank and press Enter to exit)"

# read user input
read foobar

# exit
if [[ $foobar == '' ]]; then
    exit
fi

# convert upper case to lower
foobar=$(echo "$foobar" | tr '[:upper:]' '[:lower:]')

# strip underscore and apostrophe
foobar=${foobar// /_}
foobar=${foobar//\'/}

# output
echo "########
"

echo "machine_name_"${foobar}

echo "
########"

# loop - execute itself (this could go against the Three Laws of Robotics)
bash lowercase_underscore.sh
    
por Mauro 06.03.2014 / 06:33

3 respostas

4

#!/bin/bash -
while 
  echo "Please enter a word:
  (leave blank and press Enter to exit)"
  IFS= read -r foobar

  [ -n "$foobar" ]
do
  foobar=${foobar,,*}

  printf '%s\n' "${foobar// /_}"
done

POSIXly:

while 
  echo "Please enter a word:
  (leave blank and press Enter to exit)"
  IFS= read -r foobar

  [ -n "$foobar" ]
do
  printf '%s\n' "$foobar" | tr ' ' _ | tr '[:upper:]' '[:lower:]'
done

Ou (como processamento de texto é melhor feito em um utilitário de processamento de texto, do que um shell):

#! /usr/bin/awk -f
function prompt() {
  print "Please enter a word:\n(leave blank and press Enter to exit)"
}
BEGIN {prompt()}
$0 == "" {exit}
{gsub(" ", "_"); print tolower($0); prompt()}
    
por 06.03.2014 / 07:52
1

Encontrei estes exemplos em SO neste Q & A intitulado: Como executar um loop for em cada caractere em uma string no BASH? .

Exemplo # 1 - destrutivo

Aqui está um script chamado onechar1.bash .

#!/bin/bash

echo "Please enter a word:
(leave blank and press Enter to exit)"
read someStr

if [[ $someStr == '' ]]; then
    exit
fi

while test -n "$someStr"; do
   c=${someStr:0:1}       # Get the first character
   echo "character is $c"
   someStr=${someStr:1}   # trim the first character
done

Quando eu executo:

$ ./onechar1.bash 
Please enter a word:
(leave blank and press Enter to exit)
My Name is Mauro
character is M
character is y
character is  
character is N
character is a
character is m
character is e
character is  
character is i
character is s
character is  
character is M
character is a
character is u
character is r
character is o
$

Exemplo # 2 - não destrutivo

Aqui está outro script, onechar2.bash :

#!/bin/bash

echo "Please enter a word:
(leave blank and press Enter to exit)"
read someStr

if [[ $someStr == '' ]]; then
    exit
fi

for (( i=0; i<${#someStr}; i++ )); do
    echo ${someStr:$i:1}
done

Quando executo este script:

$ ./onechar2.bash 
Please enter a word:
(leave blank and press Enter to exit)
My Name is Mauro
M
y

N
a
m
e

i
s

M
a
u
r
o
$
    
por 06.03.2014 / 07:14
1

Aqui está pelo menos um método portátil Posix que depende apenas de builtins de shell (com a possível exceção de printf ), faturamento de parâmetro (Posix) e tenta fazer o loop o mínimo possível:

lowerunder() { local c="${1%[A-Z ]*}" 
    set -- "$1" "$c" "${1#"$c"}"
    [ -z "$3" ] && printf %s "$1" || {            
        c="${3%"${3#?}"}"
        [ -z "${c#[ ]}" ] && c=_
        [ -z "${c#[A-Z]}" ] && { 
            c="$(printf %x "'$c")";
            c="$(printf %b "\x$((c+20))")" ; }
        lowerunder "${2}${c}${3#?}"
} ; }

Alimente um argumento entre aspas e substituirá os espaços dentro e todos os caracteres maiúsculos por um valor menor.

Alimente dois ou mais e ele ainda retornará seu primeiro argumento convertido para todos em minúsculos e espaços convertidos em sublinhados. Não faz muito.

Confesso que não sou bom com matemática hexadecimal e que pode ser um ponto fraco aqui - eu uso o printf para converter de código de caractere Ascii para valor hexadecimal em decimal e vice-versa. Ainda assim, foi divertido escrever.

    
por 06.03.2014 / 09:10