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 16:45:51 +0800

2012/8/17 郑文辉(Techlive Zheng) <techlivezheng@gmail.com>:
> 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

I have tried using a named pipe or process substition, neither worked.



reply via email to

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