Substituição de string computada dinamicamente com ferramentas padrão

1

Existe um mecanismo UNIX para substituir dinamicamente cadeias combinadas - com uma função da cadeia combinada?

Por exemplo, queremos substituir as correspondências de URL por suas contrapartes codificadas por URL ou converter determinadas correspondências de snake_case para camelCase ou apenas em maiúsculas?

Ruby tem o método gsub que usa um lambda ("um bloco" no jargão do ruby), mas prefiro não usar o ruby.

Eu tentei com ferramentas padrão e FIFO, mas continuo perdendo espaço em branco em torno de minhas correspondências em algum lugar na parte read (veja abaixo). Algum palpite?

#!/bin/bash

d="\f" #<=A character that's not expected in the input
swapNewlines() { tr "$d"'\n' '\n'"$d"; }  #Since unix tools are line-oriented

#Sample transformation -- coloring red
export C_red="$(tput setaf 1)"
export C_normal="$(tput sgr0)"
transform(){ printf "$C_red%s\n$C_normal" "$*"; }

even() { sed -n '2~2p'; }
odd() { sed -n '1~2p'; }

#Open an anonymous FIFO and assign that FD to variable whose names comes on $1
mkchan(){
  local __name="${1:-FD}" __tmpd= __ret=1
  if __tmpd="'mktemp -d'" && mkfifo "$__tmpd/p" && eval "exec {"$__name"}<>"'$__tmpd/p'; then
    __ret=0
  fi
  rm -rf "$__tmpd" 
  return "$__ret"
}

#No-op
df  |sed 's/\<[1]*\>/'"$d"'
#!/bin/bash

d="\f" #<=A character that's not expected in the input
swapNewlines() { tr "$d"'\n' '\n'"$d"; }  #Since unix tools are line-oriented

#Sample transformation -- coloring red
export C_red="$(tput setaf 1)"
export C_normal="$(tput sgr0)"
transform(){ printf "$C_red%s\n$C_normal" "$*"; }

even() { sed -n '2~2p'; }
odd() { sed -n '1~2p'; }

#Open an anonymous FIFO and assign that FD to variable whose names comes on $1
mkchan(){
  local __name="${1:-FD}" __tmpd= __ret=1
  if __tmpd="'mktemp -d'" && mkfifo "$__tmpd/p" && eval "exec {"$__name"}<>"'$__tmpd/p'; then
    __ret=0
  fi
  rm -rf "$__tmpd" 
  return "$__ret"
}

#No-op
df  |sed 's/\<[1]*\>/'"$d"'%pre%'"$d"'/g' | swapNewlines | swapNewlines |tr -d "$d"
printf '%s\n' -------------------------------------------------------

mkchan fd; export fd
#Surround matches with the "$d" character and swap newlines with fd; then do line-processing
df  |sed 's/\<[1]*\>/'"$d"'%pre%'"$d"'/g' | swapNewlines | 
   tee >(even >&"$fd") | 
   odd | while read o; 
          do printf "%s\n" "$o"
            read e <&"$fd"
            #printf '%s\n' "$e"
            transform "$e"
          done  |
          swapNewlines |tr -d "$d"
'"$d"'/g' | swapNewlines | swapNewlines |tr -d "$d" printf '%s\n' ------------------------------------------------------- mkchan fd; export fd #Surround matches with the "$d" character and swap newlines with fd; then do line-processing df |sed 's/\<[1]*\>/'"$d"'%pre%'"$d"'/g' | swapNewlines | tee >(even >&"$fd") | odd | while read o; do printf "%s\n" "$o" read e <&"$fd" #printf '%s\n' "$e" transform "$e" done | swapNewlines |tr -d "$d"
    
por PSkocik 01.01.2016 / 18:21

1 resposta

3

As ferramentas padrão para a substituição de strings de computador dinamicamente são o próprio shell e AWK . O sh padrão tem algumas construções de manipulação de strings e o bash tem mais algumas; você normalmente os usaria ao fazer algo simples o suficiente em uma pequena quantidade de dados. AWK é uma linguagem Turing completa, com construções imperativas clássicas (atribuição de variáveis, arrays de strings e mapas de strings para strings, if statements, while loops,…) e primitivas de manipulação de string (concatenação, divisão, correspondência de regex e substituição (mas sem grupos de jogos),…). (E também há sed, que é Turing-complete, mas fica muito peludo assim que você vai além de um simples substituto de regex).

A principal razão pela qual o espaço em branco seria perdido é porque você esqueceu de citar uma expansão variável . Você também precisa tomar cuidado ao usar read : seu trabalho é dividir as linhas em campos, portanto, se você quiser ler uma linha literalmente, precisará IFS= read -r .

Eu não revi completamente o seu script - parece bastante complexo para o que ele está fazendo - mas você provavelmente quer while IFS= read -r o em vez de while read o , se você quiser preservar o espaço em branco. No entanto, para pós-processar a saída de df , você deve usar algo como

df -P | awk '…'
    
por 02.01.2016 / 04:03