3 votes

Contournement de la substitution de processus dans mksh

Une fonctionnalité extrêmement utile de Bash, connue sous le nom de substitution de processus est absent du shell Android, mksh . C'est très malheureux car cela vous empêche de faire des choses comme :

diff <(sort list1) <(sort list2)

Le site mksh a marqué cela comme un "plan futur". aquí . Ma question est donc la suivante :

Existe-t-il des solutions de contournement pour cela ? (Et qu'est-ce qu'ils sont ?)

4voto

not2qubit Points 817

Apparemment, le seul moyen ( ?) de le faire est d'utiliser un fichier de type tuyau nommé comme ça :

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

Cela doit être mis dans un mksh afin d'être réellement utilisable en ligne de commande. Une autre partie délicate semble être qu'AOS a implémenté une sorte de délai d'attente qui tue ou perturbe le tuyau, s'il n'est pas utilisé dans un délai de quelques secondes. (Raison inconnue.)

2voto

Stu Points 169

Nous Je viens de comprendre comment faire ça pour le cas de Desktop Unix. Sur Android, vous aurez besoin d'un répertoire où placer les FIFO temporaires (n'importe quel répertoire fera l'affaire, tel que /sqlite_stmt_journal dans Android 2.x et /data/data (si vous avez le droit d'y écrire) dans les plus récentes). Vous aurez également besoin mktemp y mkfifo . ( cat est un buildin mksh de nos jours, mais sur les anciens Android, vous devrez ajouter cette version ou une version mksh plus récente ; elles fonctionnent toutes jusqu'à Android 1.5 au moins)

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 Points 99

Vous avez besoin d'un shell tel que ksh, zsh, ou bash pour la substitution de processus. Je suppose que la commande diff à laquelle @user1147688 fait référence est celle de busybox. La substitution de processus ne fonctionne pas avec les applications de busybox. Busybox diffère de diffutils diff pour la gestion des tuyaux nommés. Après un peu plus de tests, j'ai découvert que je ne pouvais utiliser la substitution de processus avec busybox diff qu'après avoir créé le répertoire /tmp avec cette commande supersu :

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

Cela crée un temporaire que tous les utilisateurs peuvent utiliser. Pour une raison quelconque, busybox n'utilise pas la variable TMPDIR. Alternativement avec zsh, vous pouvez utiliser busybox diff comme ceci :

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

C'est comme diff <(...) <(...) mais il utilise des fichiers temporaires au lieu de tuyaux nommés. Zsh utilisera le répertoire temporaire en lecture-écriture que vous avez assigné à TMPDIR. Utilisation de TMPDIR=/sdcard ne fonctionnera pas ici puisque vous ne pouvez pas changer la propriété ou les permissions sur les fichiers /sdcard.

Diffutils diff fonctionne sans aucun problème en utilisant n'importe quel type de substitution de processus.

Voici une fonction qui implémente quelque chose comme diff avec une substitution de processus. Vous pouvez l'utiliser avec busybox diff et tout shell moderne compatible sh qui supporte les tableaux, comme ksh, bash, zsh ou mksh. Cela fonctionnera en supposant que HOME est défini sur un emplacement accessible en lecture-écriture, comme /sdcard sur 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
}

Vous pouvez ajouter des tuyaux, | à votre COMMANDE1 ou COMMANDE2, à condition de les citer ou de les mettre en antislash.

Cela fonctionne en divisant l'entrée en deux tableaux avec -- comme séparateur des commandes. Quelques eval L'abus aide à séparer l'entrée et est nécessaire pour évaluer les commandes qui utilisent des pipes.

La fonction pourrait être encore modifiée pour inclure des options pour diff, soit en utilisant un troisième tableau, soit en analysant avec getopts / GNU getopt. Un troisième tableau avec un autre -- Le séparateur fonctionnerait probablement mieux pour éviter d'avoir à utiliser GNU getopt pour les options longues.

androidalle.com

AndroidAlle est une communauté de androiders où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X