3 votos

Solución para la sustitución de procesos en mksh

Una característica extremadamente útil de Bash, conocida como sustitución de procesos falta en el shell de Android, mksh . Esto es muy desafortunado, ya que le impide hacer cosas como:

diff <(sort list1) <(sort list2)

El sitio mksh ha marcado esto como un "plan futuro" aquí . Así que mis preguntas son:

¿Hay alguna solución? (¿Y cuáles son?)

0 votos

AFAIK usted es libre de utilizar cualquier otro shell, suponiendo que es compatible con Android.

0 votos

En la actualidad existe un mksh etiqueta ;-)

4voto

user1147688 Puntos 238

Aparentemente, la única forma de hacerlo es utilizando un botón tubería con nombre así:

mkfifo myp1 || exit
mkfifo myp2 || exit
sort list1 >myp1 &
sort list2 >myp2 &
diff myp1 myp2 
rm -f myp1 myp2

Para ello es necesario mksh para que sea realmente útil en la línea de comandos. Otra parte complicada parece ser que AOS ha implementado algún tipo de tiempo de espera que mata o estropea la tubería, si no se utiliza en unos pocos segundos. (Razón desconocida.)

2voto

mirabilos Puntos 165

Nosotros Acabo de descubrir cómo hacer esto para el caso de Desktop Unix. En Android, necesitarás un directorio en el que colocar los FIFOs temporales (cualquiera servirá, como por ejemplo /sqlite_stmt_journal en Android 2.x y /data/data (si tiene los derechos para escribir allí) en las más recientes). También necesitará mktemp y mkfifo . ( cat es un mksh builtin en estos días, pero en Android de edad tendrá que añadir que o una versión más reciente mksh; todos ellos trabajan hasta por lo menos Android 1.5)

function die {
        print -ru2 -- "E: $*"
        exit 1
}

function psubin {
        local stdin=$(cat; echo .) pipe

        pipe=$(mktemp /tmp/psub.XXXXXXXXXX) || die mktemp

        # this is racy
        rm -f "$pipe"
        mkfifo "$pipe" || die mkfifo

        (
                # don’t block parent
                exec <&- >&- 2>&-
                # write content to FIFO
                print -nr -- "${stdin%.}" >"$pipe"
                # signal EOF to reader, ensure it’s not merged
                sleep 0.1
                :>"$pipe"
                # clean up
                (sleep 1; rm -f "$pipe") &
        ) &
        print -nr -- "$pipe"
}

diff -u $(sort list1 | psubin) $(sort list2 | psubin)

0voto

jan Puntos 99

Necesitas un shell como ksh, zsh o bash para la sustitución de procesos. Supongo que el comando diff al que se refiere @user1147688 es de busybox. Sustitución de procesos no funciona con aplicaciones busybox. Busybox diff maneja las tuberías con nombre de forma diferente a diffutils diff. Después de un poco más de pruebas, me encontré con que sólo era capaz de utilizar la sustitución de procesos con busybox diff después de crear el directorio /tmp con este comando supersu:

su -mm -d -c 'mount -t tmpfs -o rw,uid=0,gid=0,mode=1777 /tmp /tmp'

Esto crea un temporal para que todos los usuarios lo utilicen. Por alguna razón, busybox no usa la variable TMPDIR. Alternativamente con zsh, puedes usar busybox diff así:

busybox diff =(sort ./a) =(sort ./b)

Esto es como diff <(...) <(...) pero utiliza archivos temporales en lugar de tuberías con nombre. Zsh utilizará cualquier directorio temporal de lectura-escritura que asignes a TMPDIR. Usando TMPDIR=/sdcard no funcionará aquí, ya que no se puede cambiar la propiedad o los permisos de los archivos /sdcard.

Diffutils diff funciona sin problemas utilizando cualquier tipo de sustitución de procesos.

Aquí hay una función que implementa algo como diff con sustitución de procesos. Puedes usar esto con busybox diff y cualquier shell moderno compatible con sh que soporte arrays, como ksh, bash, zsh, o mksh. Funcionará asumiendo que HOME está configurado en una ubicación de lectura-escritura, como /sdcard en Android.

# usage: diff2 COMMANDS1 -- COMMANDS2
diff2() {
        local i=1 j k cmd1 cmd2 list1 list2
        cmd1=()
        cmd2=()
        while (( i < $# )); do
                eval j="\$$i"
                if [[ $j = -- ]]; then
                        k=$i
                        break
                else
                        cmd1+=("$j")
                fi
                let i++
        done
        shift $k
        cmd2=("$@")
        list1=$HOME/diff$RANDOM
        list2=$HOME/diff$RANDOM
        eval "${cmd1[@]}" > $list1 2>&1
        eval "${cmd2[@]}" > $list2 2>&1
        diff $list1 $list2
        rm $list1 $list2
}

Puedes añadir tuberías, | a su COMANDO1 o COMANDO2 siempre que los entrecomille o les ponga barra invertida.

La forma en que esto funciona es dividiendo la entrada en dos matrices con -- como separador de los comandos. Algunos eval El abuso ayuda a separar la entrada y es necesario para evaluar los comandos que utilizan tuberías.

La función podría modificarse aún más para incluir opciones para diff, ya sea utilizando una tercera matriz o analizando con getopts / GNU getopt. Un tercer array con otro -- separador probablemente funcionaría mejor para evitar tener que usar GNU getopt para opciones largas.

0 votos

Hay algo mal con tu comando mount. Creo que debería ser: mount -t tmpfs -o rw,uid=0,gid=0,mode=1777 tmpfs /tmp y además necesita mkdir -p /tmp y volver a montar / como RW . Sin embargo, gracias por la respuesta útil y la secuencia de comandos.

PreguntAndroid.com

PreguntAndroid es una comunidad de usuarios de Android en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X