[Top][All Lists]
[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) <address@hidden>:
> 2012/8/17 郑文辉(Techlive Zheng) <address@hidden>:
>> 2012/8/17 Chet Ramey <address@hidden>:
>>> On 8/16/12 10:11 PM, 郑文辉(Techlive Zheng) wrote:
>>>> 2012/8/17 Chet Ramey <address@hidden>:
>>>>> 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 address@hidden 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.