Bash で $PATH 変数からパスを削除する最もエレガントな方法は何ですか?
-
21-08-2019 - |
質問
より一般的には、Bash 環境変数のコロンで区切られたリストから項目を削除するにはどうすればよいでしょうか?
Bash の変数拡張のより高度な形式を使用して、これを行う簡単な方法を何年も前に見たはずだったのですが、もしそうなら、私はそれを忘れてしまいました。Google で簡単に検索すると、関連する結果は驚くほど少なく、「シンプル」または「エレガント」と呼べるような結果は見つかりませんでした。たとえば、sed と awk をそれぞれ使用する 2 つの方法は次のとおりです。
PATH=$(echo $PATH | sed -e 's;:\?/home/user/bin;;' -e 's;/home/user/bin:\?;;')
PATH=!(awk -F: '{for(i=1;i<=NF;i++){if(!($i in a)){a[$i];printf s$i;s=":"}}}'<<<$PATH)
単純なものは存在しないのでしょうか?Bashのsplit()関数に似たものはありますか?
アップデート:
私の意図的に曖昧な質問についてお詫びする必要があるようです。私は特定のユースケースを解決することよりも、良い議論を引き起こすことに興味がありました。幸いなことに、私はそれを手に入れました!
ここには非常に巧妙なテクニックがいくつかあります。最終的に、次の 3 つの関数をツールボックスに追加しました。path_remove で魔法が起こります。これは主に Martin York の巧みな使い方に基づいています。 awk
の RS 変数。
path_append () { path_remove $1; export PATH="$PATH:$1"; }
path_prepend () { path_remove $1; export PATH="$1:$PATH"; }
path_remove () { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`; }
そこにある唯一の本当の難関は、 sed
末尾のコロンを削除します。ただし、Martin の残りのソリューションがどれほど単純であるかを考えると、私はそれを喜んで受け入れます。
解決
awk で 1 分:
# Strip all paths with SDE in them.
#
export PATH=`echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}'`
編集:以下のコメントに応答します。
$ export a="/a/b/c/d/e:/a/b/c/d/g/k/i:/a/b/c/d/f:/a/b/c/g:/a/b/c/d/g/i"
$ echo ${a}
/a/b/c/d/e:/a/b/c/d/f:/a/b/c/g:/a/b/c/d/g/i
## Remove multiple (any directory with a: all of them)
$ echo ${a} | awk -v RS=: -v ORS=: '/a/ {next} {print}'
## Works fine all removed
## Remove multiple including last two: (any directory with g)
$ echo ${a} | awk -v RS=: -v ORS=: '/g/ {next} {print}'
/a/b/c/d/e:/a/b/c/d/f:
## Works fine: Again!
セキュリティ問題に応じて編集します:(それは質問とは関係ありません)
export PATH=$(echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}' | sed 's/:*$//')
これにより、最後のエントリを削除することによって残った末尾のコロンが削除され、事実上追加されます。 .
あなたの道へ。
他のヒント
私の汚いハック:
echo ${PATH} > t1
vi t1
export PATH=$(cat t1)
置換の大きな問題はエンドケースであるため、エンドケースを他のケースと変わらないようにしてはどうでしょうか?パスの先頭と末尾にすでにコロンが含まれている場合は、コロンで囲まれた目的の文字列を検索するだけで済みます。現状では、これらのコロンを簡単に追加したり、後で削除したりできます。
# PATH => /bin:/opt/a dir/bin:/sbin
WORK=:$PATH:
# WORK => :/bin:/opt/a dir/bin:/sbin:
REMOVE='/opt/a dir/bin'
WORK=${WORK/:$REMOVE:/:}
# WORK => :/bin:/sbin:
WORK=${WORK%:}
WORK=${WORK#:}
PATH=$WORK
# PATH => /bin:/sbin
純粋なバッシュ:)。
私が考案できる最も簡単な解決策は次のとおりです。
#!/bin/bash
IFS=:
# convert it to an array
t=($PATH)
unset IFS
# perform any array operations to remove elements from the array
t=(${t[@]%%*usr*})
IFS=:
# output the new array
echo "${t[*]}"
上記の例では、$PATH 内の「usr」を含む要素をすべて削除します。「*usr*」を「/home/user/bin」に置き換えると、その要素だけを削除できます。
アップデート あたり シューベルト
スペースが入っていると思いますが、 $PATH
エリア 最悪 アイデアとして、これを処理するソリューションを次に示します。
PATH=$(IFS=':';t=($PATH);n=${#t[*]};a=();for ((i=0;i<n;i++)); do p="${t[i]%%*usr*}"; [ "${p}" ] && a[i]="${p}"; done;echo "${a[*]}");
または
IFS=':'
t=($PATH)
n=${#t[*]}
a=()
for ((i=0;i<n;i++)); do
p="${t[i]%%*usr*}"
[ "${p}" ] && a[i]="${p}"
done
echo "${a[*]}"
これは次のような解決策です。
- 純粋なバッシュです、
- 他のプロセス (「sed」や「awk」など) を呼び出しません。
- 変わらない
IFS
, - サブシェルをフォークしません。
- スペースを含むパスを処理します。
にある引数をすべて削除します。
PATH
.removeFromPath() { local p d p=":$1:" d=":$PATH:" d=${d//$p/:} d=${d/#:/} PATH=${d/%:/} }
関数 __path_remove(){
ローカル D=":${PATH}:";
[ "${D/:$1:/:}" != "$D" ] && PATH="${D/:$1:/:}";
PATH="${PATH/#:/}";
エクスポート PATH="${PATH/%:/}";
}
.bashrc ファイルから取り出しました。PATH をいじってみてそれが失われると、awk/sed/grep が使用できなくなります :-)
私がこれまでに見つけた最高の純粋な bash オプションは次のとおりです。
function path_remove {
PATH=${PATH/":$1"/} # delete any instances in the middle or at the end
PATH=${PATH/"$1:"/} # delete any instances at the beginning
}
これは、 完全に正しい答えではない に $PATH にディレクトリが存在しない場合は追加します。 スーパーユーザーについては以上です。
私は bash ディストリビューションの関数を使っているだけですが、この関数は 1991 年から存在しているようです。これらはまだ Fedora の bash-docs パッケージに含まれており、以前は で使用されていました。 /etc/profile
, 、でもそれ以上は...
$ rpm -ql bash-doc |grep pathfunc
/usr/share/doc/bash-4.2.20/examples/functions/pathfuncs
$ cat $(!!)
cat $(rpm -ql bash-doc |grep pathfunc)
#From: "Simon J. Gerraty" <sjg@zen.void.oz.au>
#Message-Id: <199510091130.VAA01188@zen.void.oz.au>
#Subject: Re: a shell idea?
#Date: Mon, 09 Oct 1995 21:30:20 +1000
# NAME:
# add_path.sh - add dir to path
#
# DESCRIPTION:
# These functions originated in /etc/profile and ksh.kshrc, but
# are more useful in a separate file.
#
# SEE ALSO:
# /etc/profile
#
# AUTHOR:
# Simon J. Gerraty <sjg@zen.void.oz.au>
# @(#)Copyright (c) 1991 Simon J. Gerraty
#
# This file is provided in the hope that it will
# be of use. There is absolutely NO WARRANTY.
# Permission to copy, redistribute or otherwise
# use this file is hereby granted provided that
# the above copyright notice and this notice are
# left intact.
# is $1 missing from $2 (or PATH) ?
no_path() {
eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac"
}
# if $1 exists and is not in path, append it
add_path () {
[ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1"
}
# if $1 exists and is not in path, prepend it
pre_path () {
[ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}"
}
# if $1 is in path, remove it
del_path () {
no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: |
sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"`
}
これに対して答えを書きました ここ (awkも使用します)。でも、それがあなたが探しているものなのかわかりません。一行に当てはめようとするのではなく、少なくとも私にはそれが何をするのか明確に見えます。ただし、要素を削除するだけの単純なワンライナーの場合は、次をお勧めします
echo $PATH | tr ':' '\n' | awk '$0 != "/bin"' | paste -sd:
置き換えるのは
echo $PATH | tr ':' '\n' |
awk '$0 != "/bin"; $0 == "/bin" { print "/bar" }' | paste -sd:
または (短いですが読みにくくなります)
echo $PATH | tr ':' '\n' | awk '$0 == "/bin" { print "/bar"; next } 1' | paste -sd:
とにかく、同じ質問とたくさんの役立つ回答については、を参照してください。 ここ.
bash では、正規表現がサポートされているため、単純に次のようにします。
PATH=${PATH/:\/home\/user\/bin/}
Bash で $PATH 変数からパスを削除する最もエレガントな方法は何ですか?
awk よりエレガントなものは何でしょうか?
path_remove () { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`;
パイソン!これは、より読みやすく保守しやすいソリューションであり、実際に希望どおりの動作をしているかどうかを簡単に検査できます。
最初のパス要素を削除したいとしますか?
PATH="$(echo "$PATH" | python -c "import sys; path = sys.stdin.read().split(':'); del path[0]; print(':'.join(path))")"
(からのパイプの代わりに、 echo
, os.getenv['PATH']
これは少し短くなり、上記と同じ結果が得られますが、Python がその環境変数を使用して何かを行うのではないかと心配しているため、関心のある環境から直接パイプすることがおそらく最善です)。
同様に末尾から削除します。
PATH="$(echo "$PATH" | python -c "import sys; path = sys.stdin.read().split(':'); del path[-1]; print(':'.join(path))")"
たとえば、.bashrc ファイルに貼り付けることができるこれらの再利用可能なシェル関数を作成するには、次のようにします。
strip_path_first () {
PATH="$(echo "$PATH" |
python -c "import sys; path = sys.stdin.read().split(':'); del path[0]; print(':'.join(path))")"
}
strip_path_last () {
PATH="$(echo "$PATH" |
python -c "import sys; path = sys.stdin.read().split(':'); del path[-1]; print(':'.join(path))")"
}
はい、たとえば PATH の最後にコロンを置くと、パスの削除が少し面倒でエラーが発生しにくくなります。
path_remove () {
declare i newPATH
newPATH="${PATH}:"
for ((i=1; i<=${#@}; i++ )); do
#echo ${@:${i}:1}
newPATH="${newPATH//${@:${i}:1}:/}"
done
export PATH="${newPATH%:}"
return 0;
}
path_remove_all () {
declare i newPATH
shopt -s extglob
newPATH="${PATH}:"
for ((i=1; i<=${#@}; i++ )); do
newPATH="${newPATH//+(${@:${i}:1})*([^:]):/}"
#newPATH="${newPATH//+(${@:${i}:1})*([^:])+(:)/}"
done
shopt -u extglob
export PATH="${newPATH%:}"
return 0
}
path_remove /opt/local/bin /usr/local/bin
path_remove_all /opt/local /usr/local
外すのが心配な場合は 重複 $PATH に、最もエレガントな方法は、私見ですが、最初からそれらを追加しないことです。1 行で:
if ! $( echo "$PATH" | tr ":" "\n" | grep -qx "$folder" ) ; then PATH=$PATH:$folder ; fi
$folder は任意のものに置き換えることができ、スペースを含めることもできます (「/home/user/my document」)
私がこれまでに見つけた最もエレガントな純粋な bash ソリューションは次のとおりです。
pathrm () {
local IFS=':'
local newpath
local dir
local pathvar=${2:-PATH}
for dir in ${!pathvar} ; do
if [ "$dir" != "$1" ] ; then
newpath=${newpath:+$newpath:}$dir
fi
done
export $pathvar="$newpath"
}
pathprepend () {
pathrm $1 $2
local pathvar=${2:-PATH}
export $pathvar="$1${!pathvar:+:${!pathvar}}"
}
pathappend () {
pathrm $1 $2
local pathvar=${2:-PATH}
export $pathvar="${!pathvar:+${!pathvar}:}$1"
}
他の提案されたソリューションのほとんどは文字列の一致のみに依存しており、次のような特殊な名前を含むパス セグメントは考慮されていません。 .
, ..
, 、 または ~
. 。以下の bash 関数は、引数とパス セグメント内のディレクトリ文字列を解決して、文字列の一致だけでなく論理ディレクトリの一致も見つけます。
rm_from_path() {
pattern="${1}"
dir=''
[ -d "${pattern}" ] && dir="$(cd ${pattern} && pwd)" # resolve to absolute path
new_path=''
IFS0=${IFS}
IFS=':'
for segment in ${PATH}; do
if [[ ${segment} == ${pattern} ]]; then # string match
continue
elif [[ -n ${dir} && -d ${segment} ]]; then
segment="$(cd ${segment} && pwd)" # resolve to absolute path
if [[ ${segment} == ${dir} ]]; then # logical directory match
continue
fi
fi
new_path="${new_path}${IFS}${segment}"
done
new_path="${new_path/#${IFS}/}" # remove leading colon, if any
IFS=${IFS0}
export PATH=${new_path}
}
テスト:
$ mkdir -p ~/foo/bar/baz ~/foo/bar/bif ~/foo/boo/bang
$ PATH0=${PATH}
$ PATH=~/foo/bar/baz/.././../boo/././../bar:${PATH} # add dir with special names
$ rm_from_path ~/foo/boo/../bar/. # remove same dir with different special names
$ [ ${PATH} == ${PATH0} ] && echo 'PASS' || echo 'FAIL'
Linux from Scratch は 3 つの Bash 関数を定義します /etc/profile
:
# Functions to help us manage paths. Second argument is the name of the
# path variable to be modified (default: PATH)
pathremove () {
local IFS=':'
local NEWPATH
local DIR
local PATHVARIABLE=${2:-PATH}
for DIR in ${!PATHVARIABLE} ; do
if [ "$DIR" != "$1" ] ; then
NEWPATH=${NEWPATH:+$NEWPATH:}$DIR
fi
done
export $PATHVARIABLE="$NEWPATH"
}
pathprepend () {
pathremove $1 $2
local PATHVARIABLE=${2:-PATH}
export $PATHVARIABLE="$1${!PATHVARIABLE:+:${!PATHVARIABLE}}"
}
pathappend () {
pathremove $1 $2
local PATHVARIABLE=${2:-PATH}
export $PATHVARIABLE="${!PATHVARIABLE:+${!PATHVARIABLE}:}$1"
}
export -f pathremove pathprepend pathappend
参照: http://www.linuxfromscratch.org/blfs/view/svn/postlfs/profile.html
@BenBlank の元の質問に対する更新に示されている 3 つの関数が気に入っています。それらを一般化するために、2 引数形式を使用します。これにより、PATH またはその他の必要な環境変数を設定できるようになります。
path_append () { path_remove $1 $2; export $1="${!1}:$2"; }
path_prepend () { path_remove $1 $2; export $1="$2:${!1}"; }
path_remove () { export $1="`echo -n ${!1} | awk -v RS=: -v ORS=: '$1 != "'$2'"' | sed 's/:$//'`"; }
使用例:
path_prepend PATH /usr/local/bin
path_append PERL5LIB "$DEVELOPMENT_HOME/p5/src/perlmods"
スペースを含むパス名を適切に処理できるようにするために、いくつかの引用符も追加していることに注意してください。
エレガントな方法がないため、これは非常に問題が発生する傾向があるため、解決策を再構成して問題を回避することをお勧めします。PATH を壊そうとするのではなく、PATH を構築してください。
あなたの本当の問題の背景が分かれば、もっと具体的に言えるのですが。当面は、ソフトウェア ビルドをコンテキストとして使用します。
ソフトウェア ビルドに関する一般的な問題は、最終的に誰かがデフォルト シェル (PATH およびその他の環境変数) をどのように設定したかが原因で、一部のマシンでソフトウェアが壊れることです。洗練された解決策は、シェル環境を完全に指定することでビルド スクリプトを耐性にすることです。ビルド スクリプトをコーディングして、コンパイラ、ライブラリ、ツール、コンポーネントなどの場所など、制御するアセンブリ部分に基づいて PATH やその他の環境変数を設定します。構成可能な各項目を個別に設定、確認し、スクリプト内で適切に使用できるようにします。
たとえば、新しい雇用主で継承した、Maven ベースの WebLogic をターゲットとした Java ビルドがあります。このビルド スクリプトは壊れやすいことで有名で、別の新入社員と私は 3 週間 (フルタイムではなく、あちこちで作業するだけですが、それでも何時間も) かけて、それをマシンで動作させるのに費やしました。重要なステップは、PATH を制御して、どの Java、どの Maven、どの WebLogic が呼び出されているかを正確に把握できるようにすることでした。これらの各ツールを指す環境変数を作成し、それらに加えて他のいくつかのツールに基づいて PATH を計算しました。同様の手法で他の構成可能な設定を調整し、最終的に再現可能なビルドを作成しました。
ちなみに、Maven は使用しないでください。Java は問題ありません。クラスタリングが絶対に必要な場合にのみ WebLogic を購入してください (ただし、それ以外の場合は不要、特に独自の機能は必要ありません)。
幸運をお祈りしています。
@litb と同様に、私は質問への回答を提供しました。シェルスクリプトで $PATH 要素を操作するにはどうすればよいですか」ということで、私の主な答えはそこにあります。
「分割」機能 bash
およびその他の Bourne シェル派生関数は、次のように最も適切に実現されます。 $IFS
, 、フィールド間の区切り文字。たとえば、位置引数を設定するには ($1
, $2
, ...) PATH の要素に追加するには、次を使用します。
set -- $(IFS=":"; echo "$PATH")
$PATH にスペースが含まれていない限り、正常に動作します。スペースを含むパス要素に対してこれを機能させるのは簡単な作業ではありません。興味のある読者に任せてください。おそらく、Perl などのスクリプト言語を使用して対処する方が簡単です。
脚本もあるんですが、 clnpath
, 、私は PATH の設定に広く使用しています。「」への回答に文書化しました。cshでPATH変数が重複しないようにする方法".
この問題を厄介にしているのは、最初と最後の要素の間のフェンスポストのケースです。この問題は、IFS を変更して配列を使用することでエレガントに解決できますが、パスを配列形式に変換した後でコロンを再導入する方法がわかりません。
ここでは、ディレクトリを 1 つ削除した、少し洗練されていないバージョンを示します。 $PATH
文字列操作のみを使用します。テストしてみました。
#!/bin/bash
#
# remove_from_path dirname
#
# removes $1 from user's $PATH
if [ $# -ne 1 ]; then
echo "Usage: $0 pathname" 1>&2; exit 1;
fi
delendum="$1"
NEWPATH=
xxx="$IFS"
IFS=":"
for i in $PATH ; do
IFS="$xxx"
case "$i" in
"$delendum") ;; # do nothing
*) [ -z "$NEWPATH" ] && NEWPATH="$i" || NEWPATH="$NEWPATH:$i" ;;
esac
done
PATH="$NEWPATH"
echo "$PATH"
Perl のワンライナーは次のとおりです。
PATH=`perl -e '$a=shift;$_=$ENV{PATH};s#:$a(:)|^$a:|:$a$#$1#;print' /home/usr/bin`
の $a
変数は削除するパスを取得します。の s
(代役)そして print
コマンドは暗黙的に動作します。 $_
変数。
ここには良いものがあります。私はこれを、最初からカモを追加しないようにするために使用します。
#!/bin/bash
#
######################################################################################
#
# Allows a list of additions to PATH with no dupes
#
# Patch code below into your $HOME/.bashrc file or where it
# will be seen at login.
#
# Can also be made executable and run as-is.
#
######################################################################################
# add2path=($HOME/bin .) ## uncomment space separated list
if [ $add2path ]; then ## skip if list empty or commented out
for nodup in ${add2path[*]}
do
case $PATH in ## case block thanks to MIKE511
$nodup:* | *:$nodup:* | *:$nodup ) ;; ## if found, do nothing
*) PATH=$PATH:$nodup ## else, add it to end of PATH or
esac ## *) PATH=$nodup:$PATH prepend to front
done
export PATH
fi
## debug add2path
echo
echo " PATH == $PATH"
echo
拡張グロビングを有効にすると、次のことが可能になります。
# delete all /opt/local paths in PATH
shopt -s extglob
printf "%s\n" "${PATH}" | tr ':' '\n' | nl
printf "%s\n" "${PATH//+(\/opt\/local\/)+([^:])?(:)/}" | tr ':' '\n' | nl
man bash | less -p extglob
拡張グロビング ワンライナー (まあ、一種の):
path_remove () { shopt -s extglob; PATH="${PATH//+(${1})+([^:])?(:)/}"; export PATH="${PATH%:}"; shopt -u extglob; return 0; }
$1 ではスラッシュをエスケープする必要はないようです。
path_remove () { shopt -s extglob; declare escArg="${1//\//\\/}"; PATH="${PATH//+(${escArg})+([^:])?(:)/}"; export PATH="${PATH%:}"; shopt -u extglob; return 0; }
PATH にコロンを追加すると、次のようなこともできます。
path_remove () {
declare i newPATH
# put a colon at the beginning & end AND double each colon in-between
newPATH=":${PATH//:/::}:"
for ((i=1; i<=${#@}; i++)); do
#echo ${@:${i}:1}
newPATH="${newPATH//:${@:${i}:1}:/}" # s/:\/fullpath://g
done
newPATH="${newPATH//::/:}"
newPATH="${newPATH#:}" # remove leading colon
newPATH="${newPATH%:}" # remove trailing colon
unset PATH
PATH="${newPATH}"
export PATH
return 0
}
path_remove_all () {
declare i newPATH extglobVar
extglobVar=0
# enable extended globbing if necessary
[[ ! $(shopt -q extglob) ]] && { shopt -s extglob; extglobVar=1; }
newPATH=":${PATH}:"
for ((i=1; i<=${#@}; i++ )); do
newPATH="${newPATH//:+(${@:${i}:1})*([^:])/}" # s/:\/path[^:]*//g
done
newPATH="${newPATH#:}" # remove leading colon
newPATH="${newPATH%:}" # remove trailing colon
# disable extended globbing if it was enabled in this function
[[ $extglobVar -eq 1 ]] && shopt -u extglob
unset PATH
PATH="${newPATH}"
export PATH
return 0
}
path_remove /opt/local/bin /usr/local/bin
path_remove_all /opt/local /usr/local
path_remove_all (プロキシによる):
-newPATH="${newPATH//:+(${@:${i}:1})*([^:])/}"
+newPATH="${newPATH//:${@:${i}:1}*([^:])/}" # s/:\/path[^:]*//g
これは非常に古いスレッドですが、この解決策は興味深いかもしれないと思いました。
PATH="/usr/lib/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
REMOVE="ccache" # whole or part of a path :)
export PATH=$(IFS=':';p=($PATH);unset IFS;p=(${p[@]%%$REMOVE});IFS=':';echo "${p[*]}";unset IFS)
echo $PATH # outputs /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
これで見つけました ブログ投稿. 。私はこれが一番好きだと思います:)
私はここにいるほとんどの人とは少し異なるアプローチをとり、次のように文字列操作だけに焦点を当てました。
path_remove () {
if [[ ":$PATH:" == *":$1:"* ]]; then
local dirs=":$PATH:"
dirs=${dirs/:$1:/:}
export PATH="$(__path_clean $dirs)"
fi
}
__path_clean () {
local dirs=${1%?}
echo ${dirs#?}
}
上記は、私が使用する最終関数の簡略化された例です。私も作成しました path_add_before
そして path_add_after
PATH に既に存在する指定したパスの前後にパスを挿入できます。
関数の完全なセットは、次の場所で利用できます。 path_helpers.sh 私の中で ドットファイル. 。これらは、PATH 文字列の先頭/中間/末尾での削除/追加/先頭への追加/挿入を完全にサポートしています。
末尾の「:」は、区切り文字ではなく行末を設定しているために発生します。私はリソースが限られたユニットを使用しており、次のような奇妙さを排除して、すべてを 1 つのスクリプトに詰め込むことを好みます。
path_remove () {
PATH="$(echo -n $PATH | awk -v RS=: -v ORS= '$0 != "'$1'"{print s _ $0;s=":"}')"
}