Bashスクリプト:一致する行にコメントを追加/削除する

Bashスクリプト:一致する行にコメントを追加/削除する

~/.zshrc次の行を含むファイルがあります

...
#export PATH="/usr/local/opt/[email protected]/bin:$PATH"
#export PATH="/usr/local/opt/[email protected]/sbin:$PATH"
##export PATH="/usr/local/opt/[email protected]/bin:$PATH"
##export PATH="/usr/local/opt/[email protected]/sbin:$PATH"
#export PATH="/usr/local/opt/[email protected]/bin:$PATH"
#export PATH="/usr/local/opt/[email protected]/sbin:$PATH"
#export PATH="/usr/local/opt/[email protected]/bin:$PATH"
#export PATH="/usr/local/opt/[email protected]/sbin:$PATH"
export PATH="/usr/local/opt/[email protected]/bin:$PATH"
export PATH="/usr/local/opt/[email protected]/sbin:$PATH"
...

私はPHPバージョン(最初のパラメータ)とタスク(2番目のパラメータ)を受け入れる小さなbashスクリプトを準備しています。たとえば、仮想コマンドは次のようになります。

mycommand 7.4 comment

これにより、ファイル内の次の行だけがコメントアウトされます。

#export PATH="/usr/local/opt/[email protected]/bin:$PATH"
#export PATH="/usr/local/opt/[email protected]/sbin:$PATH"

走れば

mycommand 7.1 uncomment

次の行だけが更新されます。

export PATH="/usr/local/opt/[email protected]/bin:$PATH"
export PATH="/usr/local/opt/[email protected]/sbin:$PATH"

sedだから私の質問は、.shスクリプトのコマンドまたは他のコマンドを使用してファイルを解析する方法です。
私のbashスクリプトは次のとおりです(動作しません)

# File mycommand.sh
# ...
if [[ ! -z "$1" && ! -z "$2" && "$2" = "comment" ]]; then
    # remove multi # comments if there's any
    sed -i '' 's/#*export PATH="\/usr\/local\/opt\/php@$1/export PATH="\/usr\/local\/opt\/php@$1/g'   
    # Finally add a single # comment
    sed -i '' 's/*export PATH="\/usr\/local\/opt\/php@$1/#export PATH="\/usr\/local\/opt\/php@$1/g'    
fi
if [[ ! -z "$1" && ! -z "$2" && "$2" = "uncomment" ]]; then
    # remove one or more # comments
    sed -i '' 's/#*export PATH="\/usr\/local\/opt\/php@$1/export PATH="\/usr\/local\/opt\/php@$1/g'   
fi

答え1

これは強力で効率的で移植可能に機能します。

#!/usr/bin/env bash

infile=~/.zshrc
tmp=$(mktemp) || exit 1

awk -v ver="$1" -v cmd="$2" '
    index($0,"php@"ver"/") {
        if      ( cmd == "comment" )   { sub(/^#*/,"#") }
        else if ( cmd == "uncomment" ) { sub(/^#+/,"")  }
        else { printf "bad cmd: %s\n", cmd | "cat>&2" }
    }
    { print }
' "$infile" > "$tmp" && mv "$tmp" "$infile"

必要に応じて、実際の入力にはありますが、例には示されていない他の行との間違った一致を防ぐように"php@"ver"/"変更してください。"export PATH=\"/usr/local/opt/php@"ver"/"

GNU awkがある場合は、-i inplacetmpファイルを手動で生成する代わりにそれを使用できます。

答え2

使用するスクリプトを次のように変更する必要があります。

if [[ ! -z "$1" && ! -z "$2" && "$2" = "comment" ]]; then
    # remove multi # comments if there's any
    sed -i "s/#*export PATH=\"\/usr\/local\/opt\/php@$1/export PATH=\"\/usr\/local\/opt\/php@$1/g" ~/.zshrc
    # Finally add a single # comment
    sed -i "s/export PATH=\"\/usr\/local\/opt\/php@$1/#export PATH=\"\/usr\/local\/opt\/php@$1/g" ~/.zshrc
fi
if [[ ! -z "$1" && ! -z "$2" && "$2" = "uncomment" ]]; then
    # remove one or more # comments
   sed -i "s/#*export PATH=\"\/usr\/local\/opt\/php@$1/export PATH=\"\/usr\/local\/opt\/php@$1/g" ~/.zshrc
fi

問題は次のとおりです。

  1. その後には空の一重引用符('')が続きますsed -i

  2. sed入力ファイル()が指定されていません~/.zshrc

  3. シェルが最初に変数を拡張するように、単一引用符()の"代わりに二重引用符()を使用する必要があります。バラより'$1これそしてこれ関連質問。

関連情報