Como uso um delimitador de vários caracteres para expansão de array no bash?

3

Estou reduzindo a questão (acredito) no caso mais simples. Digamos que eu tenha um script myscript.sh com o seguinte conteúdo:

#!/bin/bash
IFS='%20'
echo "$*"

Se eu executar o comando da seguinte maneira, a saída será semelhante a:

me@myhost ~ $ ./myscript.sh fee fi fo fum
fee%fi%fo%fum

Esse é o comportamento esperado, conforme descrito na página bash man:

   *      Expands  to  the positional parameters, starting from one.  When
          the expansion occurs within double quotes, it expands to a  sin-
          gle word with the value of each parameter separated by the first
          character of the IFS special variable.  That is, "$*" is equiva-
          lent to "$1c$2c...", where c is the first character of the value
          of the IFS variable.  If IFS is unset, the parameters are  sepa-
          rated  by  spaces.   If  IFS  is null, the parameters are joined
          without intervening separators. 

No entanto, o que eu gostaria de obter é a saída:

fee%20fi%20fo%20fum

Assim, usando um campo separador de múltiplos caracteres em vez de um único caractere.

Existe uma maneira de fazer isso que é nativo para bash ?

ATUALIZAÇÃO:

Com base nos dados do mikeserv abaixo e no writeup em Por que é printf melhor que echo? , acabei fazendo o seguinte (novamente reduzido ao caso mais simples como no exemplo acima):

#!/bin/bash
word="$1"
shift
if [ "$#" -gt 0 ] ; then
    word="$word$(printf '%%20%s' "$@")"
fi
printf '%s\n' "$word"
unset word
    
por Wildcard 12.10.2015 / 06:16

3 respostas

4

printf aplica sua string de formato a cada argumento que a segue na saída. É um bash shell embutido e pode ser usado para aplicar uma string delimitadora a uma lista de argumentos - tipo de.

Por exemplo:

printf %s:delimit: arg1 arg2 arg3
arg1:delimit:arg2:delimit:arg3:delimit:

A coisa é, printf não para aplicar sua string de formato no final de seus argumentos, e o último recebe um delimitador anexado. Isso pode ser tratado em alguns casos:

printf %b:delimit: \0150 \0145 \0171\c
h:delimit:e:delimit:y

printf interpreta C e octal escapa como %b ytes com um determinado tipo de formato, e também com o formato %b you \c ut sua saída em um determinado ponto, e é por isso que printf faz não siga o y acima com uma string :delimit: , como a string de formatação indicaria.

Então, se você quiser que todo argumento literalmente interpretado e não seja um delimitador final, então você terá que resolver o problema dentro da própria lista de argumentos:

set -- arg1 arg2 arg3
for arg do shift
    set -- "$@" :delimit: "$arg"
done; shift
printf %s "$@"
arg1:delimit:arg2:delimit:arg3
    
por 12.10.2015 / 07:17
2

Em zsh , você pode usar j:string: Parâmetros Expansion flag :

set -- fee fi fo fum
delims=%20
print -rl ${(j:$delims:)@}
    
por 12.10.2015 / 08:42
-1

Se você usar bash (ou outro shell com expansão de variável ativada) e os argumentos não tiverem espaços dentro de você, faça:

#!/bin/bash
line=$*
echo "${line// /:delimiter:}"

No caso de espaços, você terá que usar outro delimitador de campo definindo IFS variable antes de line .

    
por 12.10.2015 / 07:50