bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: `history -r` can not read from /dev/stdin ?


From: Techlive Zheng
Subject: Re: `history -r` can not read from /dev/stdin ?
Date: Fri, 17 Aug 2012 15:15:32 +0800

2012/8/17 郑文辉(Techlive Zheng) <techlivezheng@gmail.com>:
> 2012/8/17 Chet Ramey <chet.ramey@case.edu>:
>> On 8/16/12 10:11 PM, 郑文辉(Techlive Zheng) wrote:
>>> 2012/8/17 Chet Ramey <chet.ramey@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    chet@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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]