Falta una característica extremadamente útil de Bash, conocida como sustitución de procesos , 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í . Entonces mi pregunta es:
¿Hay alguna solución para esto? (¿Y qué son?)
Aparentemente, la única (?) forma de hacer esto es mediante el uso de una canalización con nombre como esta:
mkfifo myp1 || exit
mkfifo myp2 || exit
sort list1 >myp1 &
sort list2 >myp2 &
diff myp1 myp2
rm -f myp1 myp2
Esto debe colocarse en una función de shell mksh para que sea de cualquier uso real de 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 usa en unos segundos. (Razón desconocida.)
Acabamos de descubrir cómo hacer esto para el caso de Desktop Unix. En Android, necesitará un directorio para colocar FIFO temporales (cualquiera servirá, como /sqlite_stmt_journal
en Android 2.x y /data/data
(si tiene los derechos para escribir allí) en los más nuevos). También necesitará mktemp
y mkfifo
. ( cat
es un mksh incorporado en estos días, pero en Android antiguo deberá agregar eso o una versión mksh más nueva; todos funcionan al menos hasta 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)
Necesita 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. La sustitución de procesos no funciona con las aplicaciones de busybox.Busybox diff maneja las canalizaciones con nombre de manera diferente a diffutils diff. Después de un poco más de pruebas, descubrí que solo podía usar la sustitución de procesos con la diferencia de busybox 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 lo usen todos los usuarios. Por alguna razón, busybox no usa la variable TMPDIR. Alternativamente con zsh, puede usar la diferencia de busybox de esta manera:
busybox diff =(sort ./a) =(sort ./b)
Esto es como diff <(...) <(...)
pero usa archivos temporales en lugar de canalizaciones con nombre. Zsh utilizará cualquier directorio temporal de lectura y escritura que asigne a TMPDIR. Sin embargo, el uso TMPDIR=/sdcard
no funcionará aquí, ya que no puede cambiar la propiedad o los permisos en 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. Puede usar esto con busybox diff y cualquier shell moderno compatible con sh que admita matrices, como ksh, bash, zsh o mksh. Funcionará suponiendo que HOME esté configurado en una ubicación de lectura y 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
}
Puede agregar conductos, |
, a su COMMAND1 o COMMAND2 siempre que los entrecomilla o barra invertida.
La forma en que esto funciona es dividiendo la entrada en dos matrices con --
el separador de los comandos. Cierto eval
abuso ayuda a separar la entrada y es necesario para evaluar comandos que usan canalizaciones.
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. Una tercera matriz con otro --
separador probablemente funcionaría mejor para evitar tener que usar GNU getopt para opciones largas.
mount -t tmpfs -o rw,uid=0,gid=0,mode=1777 tmpfs /tmp
y además necesitas volver a mkdir -p /tmp
montarlo /
como RW . Sin embargo, gracias por la respuesta útil y el guión.
Árbol Gigante
Mirabilios