I like keeping my history files uncluttered. Since zsh has excellent history searching features, there is no need to save all the commands that I repeatedly use (e.g., finger, pwd, ls, etc) multiple times. To strip the history file of all duplicate lines, I did sort .zhistory|uniq -du
. Now, I'd like to write this back to the same file, so that if I simply put this in my .zshrc
, everytime I开发者_运维技巧 login, my history is trimmed and clean. If I try sort .zhistory|uniq -du>.zhistory
, the resulting file is empty! On the other hand, if I do sort .zhistory|uniq -du>tempfile
, it writes to tempfile
correctly. Any idea how I can write to the same file?
You might be able to use a variable:
file='.zhistory' && var=$(sort -u "$file") && echo "$var" > "$file"
The reason you can't write to the same file is that the redirection occurs first and truncates the file before the utility ever sees it.
You can prevent duplicate lines in the first place. Use setopt
with one or more of the following settings (from man zshoptions
):
HIST_EXPIRE_DUPS_FIRST
If the internal history needs to be trimmed to add the current command line, setting this option will cause the oldest history event that has a duplicate to be lost before losing a unique event from the list. You should be sure to set the value of HISTSIZE to a larger number than SAVEHIST in order to give you some room for the duplicated events, otherwise this option will behave just like HIST_IGNORE_ALL_DUPS once the history fills up with unique events.HIST_FIND_NO_DUPS
When searching for history entries in the line editor, do not display duplicates of a line previously found, even if the duplicates are not contiguous.HIST_IGNORE_ALL_DUPS
If a new command line being added to the history list duplicates an older one, the older command is removed from the list (even if it is not the previous event).HIST_IGNORE_DUPS (-h)
Do not enter command lines into the history list if they are duplicates of the previous event.HIST_SAVE_NO_DUPS
When writing out the history file, older commands that duplicate newer ones are omitted.
The program sponge can be useful to write back in the same file you read.
(For the example's sake, you don't know about sed -i)
echo "say what again" > file
sed s/what/woot/ file > file
So bad, file is now empty, you lost your file.
echo "say what again" > file
sed s/what/woot/ file | sponge file
does what you want
(Be careful not to write sponge > file
or the file will be empty again.)
The fact that i didn't have an answer to this question annoyed me sufficiently that i wrote one - call this inplace and put it executably on your path:
#! /bin/bash
BACKUP_EXT=
while getopts "b:" flag
do
case "$flag" in
b) BACKUP_EXT="$OPTARG" ;;
esac
done
shift $((OPTIND - 1))
CMD="$1"
shift
for filename in "$@"
do
TMP_FILE="$(mktemp -t)"
bash -c "$CMD" <"$filename" >"$TMP_FILE"
if [[ -n "$BACKUP_EXT" ]]
then
mv "$filename" "$filename.$BACKUP_EXT"
fi
mv "$TMP_FILE" "$filename"
done
You may now say:
inplace 'sort | uniq -du' .zhistory
Incidentally, there's a way to do that uniqification without having to sort - but that's an answer for another question!
精彩评论