2012/8/17 郑文辉(Techlive Zheng) <techlivezh...@gmail.com>: > 2012/8/17 Chet Ramey <chet.ra...@case.edu>: >> On 8/16/12 10:11 PM, 郑文辉(Techlive Zheng) wrote: >>> 2012/8/17 Chet Ramey <chet.ra...@case.edu>: >>>> On 8/16/12 9:17 AM, 郑文辉(Techlive Zheng) wrote: >>>>> I was trying to reload the bash history file which changed by another >>>>> bash session with the following commands, but it wouldn't work, please >>>>> help me, why? >>>>> >>>>> ``` >>>>> new_history=$(history -a /dev/stdout) >>>>> history -c >>>>> history -r >>>>> echo "$new_history" | history -r /dev/stdin >>>>> ``` >>>> >>>> One possible cause that springs to mind is the fact that the `history -r' >>>> at the end of the pipeline is run in a subshell and cannot affect its >>>> parent's history list. >>> >>> So, How could I accomplish this kind of thing? >> >> Why not just use a regular file? >> >> -- >> ``The lyf so short, the craft so long to lerne.'' - Chaucer >> ``Ars longa, vita brevis'' - Hippocrates >> Chet Ramey, ITS, CWRU c...@case.edu http://cnswww.cns.cwru.edu/~chet/ > > Actually, I was tring to erase duplicate entries and share history > across bash sessions.'erasedups' in `HISTCONTROL` only have effect for > history list in the memory, so my solution is to load entire history > file into memory and save it after every command finished. > > Here is what I am currently have in .bashrc, and it works as expected. > > reload_history() { > local HISTHASH_NEW=`md5sum $HOME/.bash_history | cut -d' ' -f1` > if [ "$HISTHASH" = "$HISTHASH_NEW" ]; then > history -w > # This is necessay because we need > # to clear the last append signture > history -c > history -r > else > HISTTEMP=`mktemp` > history -a $HISTTEMP > history -c > history -r > history -r $HISTTEMP > history -w > rm $HISTTEMP > fi > HISTHASH=`md5sum $HOME/.bash_history | cut -d' ' -f1` > } > > export PROMPT_COMMAND="reload_history;$PROMPT_COMMAND" > > Considering `mkemp` then remove the temp file on every prompt command > is a little bit expensive, I want to directly pipe the output of the > `history -a` to `hisotory -r` like below, unfortunately, this wouldn't > work, because `history -r` could not handle /dev/stdin. > > reload_history() { > local HISTHASH_NEW=`md5sum $HOME/.bash_history | cut -d' ' -f1` > if [ "$HISTHASH" = "$HISTHASH_NEW" ]; then > history -w > # This is necessay because we need > # to clear the last append signture > history -c > history -r > else > new_history=$(history -a /dev/stdout) > history -c > history -r > echo "$new_history" | history -r /dev/stdin > history -w > fi > HISTHASH=`md5sum $HOME/.bash_history | cut -d' ' -f1` > } > > export PROMPT_COMMAND="reload_history;$PROMPT_COMMAND"
I have just checked out the source of bash and found that `read()` or `mmap` is used to read the history file as below. The following code could not handle /dev/stdin properly. As I am not a C expert, I could not come up a patch for this, maybe someone here could give me a little help? >From lib/readline/histfile.c:200 #ifdef HISTORY_USE_MMAP /* We map read/write and private so we can change newlines to NULs without affecting the underlying object. */ buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0); if ((void *)buffer == MAP_FAILED) { errno = overflow_errno; goto error_and_exit; } chars_read = file_size; #else buffer = (char *)malloc (file_size + 1); if (buffer == 0) { errno = overflow_errno; goto error_and_exit; } chars_read = read (file, buffer, file_size); #endif