Ein äußerst nützliches Feature von Bash, bekannt als Process Substitution , fehlt in der Android-Shell, mksh . Dies ist sehr bedauerlich, da es Sie daran hindert, Dinge zu tun wie:
diff <(sort list1) <(sort list2)
Die mksh-Site hat dies hier als "Zukunftsplan" gekennzeichnet . Also meine Fragen sind:
Gibt es Workarounds dafür? (Und was sind sie?)
Anscheinend ist die einzige (?) Möglichkeit, dies zu tun, die Verwendung einer benannten Pipe wie dieser:
mkfifo myp1 || exit
mkfifo myp2 || exit
sort list1 >myp1 &
sort list2 >myp2 &
diff myp1 myp2
rm -f myp1 myp2
Dies muss in eine mksh- Shell-Funktion eingefügt werden, um von einer echten Befehlszeilenverwendung zu sein. Ein weiterer kniffliger Teil scheint zu sein, dass AOS eine Art Zeitüberschreitung implementiert hat, die die Pipe tötet oder durcheinander bringt, wenn sie nicht innerhalb weniger Sekunden verwendet wird. (Grund unbekannt.)
Wir haben gerade herausgefunden, wie das für den Desktop-Unix-Fall geht. Unter Android benötigen Sie ein Verzeichnis, in dem Sie temporäre FIFOs ablegen können (jedes reicht aus, z. B. /sqlite_stmt_journal
in Android 2.x und /data/data
(wenn Sie die Rechte haben, dort zu schreiben) in neueren). Sie benötigen außerdem mktemp
und mkfifo
. ( cat
ist heutzutage ein eingebautes mksh, aber auf altem Android müssen Sie diese oder eine neuere mksh-Version hinzufügen; sie funktionieren alle bis mindestens 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)
Sie benötigen eine Shell wie ksh, zsh oder bash für die Prozessersetzung.Ich gehe davon aus, dass der Diff-Befehl @ user1147688 von busybox stammt. Die Prozessersetzung funktioniert nicht mit Busybox-Apps.Busybox diff behandelt benannte Pipes anders als diffutils diff. Nach ein wenig mehr Tests stellte ich fest, dass ich die Prozesssubstitution nur mit busybox diff verwenden konnte, nachdem ich das /tmp-Verzeichnis mit diesem Supersu-Befehl erstellt hatte:
su -mm -d -c 'mount -t tmpfs -o rw,uid=0,gid=0,mode=1777 /tmp /tmp'
Dadurch wird eine temporäre Datei erstellt, die alle Benutzer verwenden können. Aus irgendeinem Grund verwendet busybox die TMPDIR-Variable nicht. Alternativ mit zsh können Sie busybox diff wie folgt verwenden:
busybox diff =(sort ./a) =(sort ./b)
Dies ist wie diff <(...) <(...)
, aber es verwendet temporäre Dateien anstelle von Named Pipes. Zsh verwendet jedes les- und beschreibbare temporäre Verzeichnis, das Sie TMPDIR zuweisen. Die Verwendung TMPDIR=/sdcard
funktioniert hier jedoch nicht, da Sie den Besitz oder die Berechtigungen für /sdcard-Dateien nicht ändern können.
Diffutils diff funktioniert ohne Probleme mit jeder Art von Prozesssubstitution.
Hier ist eine Funktion, die so etwas wie diff mit Prozesssubstitution implementiert. Sie können dies mit busybox diff und jeder modernen sh-kompatiblen Shell verwenden, die Arrays unterstützt, wie z. B. ksh, bash, zsh oder mksh. Es funktioniert, vorausgesetzt, HOME ist auf einen Ort mit Lese- und Schreibzugriff eingestellt, z. B. /sdcard auf 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
}
Sie können Pipes, |
, zu Ihrem COMMAND1 oder COMMAND2 hinzufügen, solange Sie sie in Anführungszeichen setzen oder mit einem Backslash versehen.
Dies funktioniert, indem die Eingabe in zwei Arrays mit --
als Trennzeichen für die Befehle aufgeteilt wird. Etwas eval
Missbrauch hilft beim Trennen der Eingabe und wird benötigt, um Befehle auszuwerten, die Pipes verwenden.
Die Funktion könnte weiter modifiziert werden, um Optionen für diff einzuschließen, entweder unter Verwendung eines dritten Arrays oder durch Parsing mit getopts / GNU getopt. Ein drittes Array mit einem anderen --
Trennzeichen würde wahrscheinlich am besten funktionieren, um zu vermeiden, GNU getopt für lange Optionen verwenden zu müssen.
mount -t tmpfs -o rw,uid=0,gid=0,mode=1777 tmpfs /tmp
und außerdem müssen Sie als RWmkdir -p /tmp
neu einhängen und einhängen . Vielen Dank jedoch für die nützliche Antwort und das Skript.
/
GiantTree
mirabilos