6

Using Terminal Emulator for Android, is there a way to enable a persistent command history?

So far, I've tried the following:

  • Initial command of export HISTFILE=$HOME/.mksh_history

  • User mksh profile /data/data/jackpal.androidterm/app_HOME/.mkshrc containing export HISTFILE=$HOME/.mksh_history

  • System mksh profile /system/etc/mkshrc containing export HISTFILE=/data/data/jackpal.androidterm/app_HOME/.mksh_history (though preferably the solution does not involve writing to /system)

I'm able to get other Android shells (ash and bash) to write histories into app_HOME without issue. I'm also able to get mksh to write HISTFILE on Linux without issue.

2
  • I believe you cannot, but I'm not 100% sure.
    – Nicholas
    Commented Jul 26, 2016 at 2:22
  • you can use a project ive built, gitlab.com/rafi-gana/superadb just install the requirements and run it.
    – rafi_gana
    Commented Jan 16, 2020 at 17:56

4 Answers 4

5

mksh developer here.

We disabled persistent history for mksh on Android, in order to not tax the flash memory with too many write requests.

You can re-enable it in a custom ROM by setting -DHAVE_PERSISTENT_HISTORY=1 in LOCAL_CFLAGS in Android.mk. You can also recompile mksh like that and copy that onto your ROM, if it’s rooted and the base OS version is the same.

Furthermore, you can copy any statically-linked binary for the same architecture on the phone and use that. The mksh-static binaries in the Debian package, however, also exclude persistent history.

If you really think this feature is worthwhile, persuade Google to enable it; for that, they need to edit mkmf.sh and remove the following lines…

# even the idea of persistent history on a phone is funny
HAVE_PERSISTENT_HISTORY=0; export HAVE_PERSISTENT_HISTORY

… then rebuild Android.mk from it (which they do for every new version anyway).

Oh, and you could ask the Terminal Emulator for Android developer to bundle a version of mksh with history enabled. This is probably no bad idea anyway, as it’ll be newer than what you get in the stock ROMs, and it won’t overwrite the system shell /system/bin/sh, but be available to CLI users.

That all still won’t enable persistent history by default (I’m strictly opposed to it, as it’s a surveillance feature), but enables users to set $HISTFILE themselves to enable it.

3
  • I agree, bundled with Terminal Emulator for Android would really be the proper place. JuiceSSH does it, but with bash instead. Anyways, in the meantime I've just compiled it and copied it over. Thanks for the info!
    – Six
    Commented Jul 26, 2016 at 10:51
  • GNU bash is tricky due to possible licence issues (GPL); also, mksh is much smaller and smoother. Furthermore, mksh builds with bionic (Android’s libc) much more easily, so the bundling has low effort needed. Glad I could help!
    – mirabilos
    Commented Jul 26, 2016 at 10:54
  • "a surveillance feature"?
    – endolith
    Commented Aug 30, 2016 at 18:58
1

I've created a hacky workaround for the history feature in mksh. As the developer (@mirabilos) stated, history was removed from the mksh build options in android.

But, you can emulate the same using PS1, history (fc) and print built-in functions:

HISTFILE="/sdcard/.adb/.history"
# first, do `print -s` for each line of the file.
# `print -s` is printing to the shell history file,which doesn't exist in this case. so its a virtual one.
if [ -f "$HISTFILE" ] ; then
    while read -r p; do print -s "$p"; done < "$HISTFILE"
fi

# after each command, we will run `add_to_history` which add the last command to the history file
add_to_history(){
  # fc -ln -1: get the last command from history without numbers.
  last_command=$(fc -ln -1 2> /dev/null)||return
  last_line=$(tail -n 1 "$HISTFILE" 2>/dev/null || true)
  if [ "$last_command" != "$last_line" ]; then # dont add the same line
     # Append the last command to the file
     echo "$last_command" >> "$HISTFILE"
  else
     return
  fi
}
# add the function to the prompt, so the shell execute it after each command
PS1="$PS1\$(add_to_history)"; 

I've also implemented that in my adb-shell repo. Look there if you want to understand how to set up the .mksh config file with adb shell

1
  • It’s cool that there are community contributions to the shell like this! Thank you. This way, people who want it can still use it.
    – mirabilos
    Commented Jul 6 at 13:37
0

To write Android shell history to file from Android terminal, type

history > /path/to/file/history.txt

If you use Termux instead of Terminal Emulator, then your history is preserved.

0

I built a working custom mksh from source on an Android device using Termux and replaced /system/bin/sh with it (rename or backup /system/bin/sh first). You need to install build-essential in Termux, then:

wget http://www.mirbsd.org/MirOS/dist/mir/mksh/mksh-R57.tgz
tar -xvf mksh-R57.tgz
cd mksh
mkdir build
cd build
sh ../Build.sh -o CFLAGS="-Wall -Werror -Wno-deprecated-declarations -fno-asynchronous-unwind-tables -fno-strict-aliasing -fwrapv -DDEBUG_LEAKS -DMKSH_ASSUME_UTF8 -DMKSH_DONT_EMIT_IDSTRING -DKSH_VERSIONNAME_VENDOR_EXT=\" Android\" -DMKSH_BUILDSH -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN -DHAVE_STRING_POOLING=1 -DHAVE_ATTRIBUTE_BOUNDED=1 -DHAVE_ATTRIBUTE_FORMAT=1 -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_PURE=1 -DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 -DHAVE_SYS_TIME_H=1 -DHAVE_TIME_H=1 -DHAVE_BOTH_TIME_H=1 -DHAVE_SYS_BSDTYPES_H=0 -DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SYS_SELECT_H=1 -DHAVE_SYS_SYSMACROS_H=1 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 -DHAVE_IO_H=0 -DHAVE_LIBGEN_H=1 -DHAVE_LIBUTIL_H=0 -DHAVE_PATHS_H=1 -DHAVE_STDINT_H=1 -DHAVE_STRINGS_H=1 -DHAVE_TERMIOS_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 -DHAVE_CAN_INTTYPES=1 -DHAVE_CAN_UCBINTS=1 -DHAVE_CAN_INT8TYPE=1 -DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=1 -DHAVE_SIG_T=1 -DHAVE_SYS_ERRLIST=0 -DHAVE_SYS_SIGNAME=1 -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1 -DHAVE_LOCK_FCNTL=1 -DHAVE_GETRUSAGE=1 -DHAVE_GETSID=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_KILLPG=1 -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1 -DHAVE_FTRUNCATE=1 -DHAVE_NICE=1 -DHAVE_REVOKE=0 -DHAVE_SETLOCALE_CTYPE=1 -DHAVE_LANGINFO_CODESET=1 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=1 -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 -DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 -DHAVE_PERSISTENT_HISTORY=1 -DMKSH_BUILD_R=571 -DMKSH_DEFAULT_PROFILEDIR=\"/system/etc\" -DMKSHRC_PATH=\"/system/etc/mkshrc\" -DMKSH_DEFAULT_EXECSHELL=\"/system/bin/sh\" -DMKSH_DEFAULT_TMPDIR=\"/data/local\" -static -PREFIX=\"/system\""

After that, edited /system/etc/mkshrc to include export HISTFILE=/sdcard/Android/.mksh_history.

This was a permanent solution, so it worked with remote adb shell and persistent after reboots. You could copy the binary to the Terminal Emulator home folder and set it as the shell command, but ~/.mkshrc ~/mkshrc ~/.profile does not appear to work, so you will also need to add export ENV=/sdcard/Android/.mkshrc to /system/etc/mkshrc.

Download the compiled binary here: sh for Android with history enabled.

*Got most of the compile flags from here.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .