[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