开发者

Bash script: only echo line to ~/.bash_profile once if the line doesn't yet exist

I wrote a bash git-install script. Toward the end, I do:

echo "Edit ~/.bash_profile to load ~/.git-completioin.bash on Terminal launch"
echo "source ~/.git-completion.bash" >> ~/.bash_profile

The problem is, if you run the script more than once, you end up appending this line multiple times to ~/.bash_profile. How do I use bash scripting with grep or sed (or another option you may recommend) to only add the line if it doesn't yet exist in the file. Also, I wan开发者_如何学运维t to add the line to ~/.profile if that file exists and ~/.bash_profile doesn't exist, otherwise just add it to ~/.bash_profile.


Something like this should do it:

LINE_TO_ADD=". ~/.git-completion.bash"

check_if_line_exists()
{
    # grep wont care if one or both files dont exist.
    grep -qsFx "$LINE_TO_ADD" ~/.profile ~/.bash_profile
}

add_line_to_profile()
{
    profile=~/.profile
    [ -w "$profile" ] || profile=~/.bash_profile
    printf "%s\n" "$LINE_TO_ADD" >> "$profile"
}

check_if_line_exists || add_line_to_profile

A couple of notes:

  • I've used the . command instead of source as source is a bashism, but .profile may be used by non-bash shells. The command source ... is an error in .profile
  • I've used printf instead of echo because it's more portable and wont screw up backslash-escaped characters as bash's echo would.
  • Try to be a little more robust to non-obvious failures. In this case make sure .profile exists and is writable before trying to write to it.
  • I use grep -Fx to search for the string. -F means fixed strings, so no special characters in the search string needs to be escaped, and -x means match the whole line only. The -qs is common grep syntax for just checking the existence of a string and not to show it.
  • This is proof of concept. I didn't actually run this. My bad, but it's Sunday morning and I want to go out and play.


if [[ ! -s "$HOME/.bash_profile" && -s "$HOME/.profile" ]] ; then
  profile_file="$HOME/.profile"
else
  profile_file="$HOME/.bash_profile"
fi

if ! grep -q 'git-completion.bash' "${profile_file}" ; then
  echo "Editing ${profile_file} to load ~/.git-completioin.bash on Terminal launch"
  echo "source \"$HOME/.git-completion.bash\"" >> "${profile_file}"
fi


How about:

grep -q '^source ~/\.git-completion\.bash$' ~/.bash_profile || echo "source ~/.git-completion.bash" >> ~/.bash_profile

or in a more explicit (and readable) form:

if ! grep -q '^source ~/\.git-completion\.bash$' ~/.bash_profile; then
    echo "Updating" ~/.bash_profile

    echo "source ~/.git-completion.bash" >> ~/.bash_profile
fi

EDIT:

You should probably add an additional newline before your one-liner, just in case ~/.bash_profile does not end in one:

if ! grep -q '^source ~/\.git-completion\.bash$' ~/.bash_profile; then
    echo "Updating" ~/.bash_profile

    echo >> ~/.bash_profile   
    echo "source ~/.git-completion.bash" >> ~/.bash_profile
fi

EDIT 2:

This is a bit easier to modify and slightly more portable:

LINE='source ~/.git-completion.bash'

if ! grep -Fx "$LINE" ~/.bash_profile >/dev/null 2>/dev/null; then
    echo "Updating" ~/.bash_profile

    echo >> ~/.bash_profile   
    echo "$LINE" >> ~/.bash_profile
fi

The -F and -x options are specified by POSIX and were suggested in several other answers and comments.


# Decide which profile to add to
PROFILE=~/.bash_profile
if ! [ -e "$PROFILE" ] && [ -e ~/.profile ]; then
    PROFILE=~/.profile
fi

# Add to profile if it doesn't appear to be there already. Err on the side of
# not adding it, in case user has made edits to their profile.
if ! grep -s 'git-completion\.bash' "$PROFILE"; then
    echo "Editing $PROFILE to load ~/.git-completion.bash on Terminal launch"
    echo "source ~/.git-completion.bash" >> "$PROFILE"
fi
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜