ما هي الطريقة الأكثر أناقة لإزالة المسار من متغير PATH $ في Bash؟
-
21-08-2019 - |
سؤال
أو بشكل أكثر عمومية، كيف يمكنني إزالة عنصر من قائمة مفصولة بنقطتين في متغير بيئة Bash؟
اعتقدت أنني رأيت طريقة بسيطة للقيام بذلك منذ سنوات، باستخدام الأشكال الأكثر تقدمًا لتوسيع متغير Bash، ولكن إذا كان الأمر كذلك فقد فقدت مسارها.أدى البحث السريع في Google إلى ظهور عدد قليل من النتائج ذات الصلة بشكل مدهش ولم يكن هناك ما يمكن أن أسميه "بسيطًا" أو "أنيقًا".على سبيل المثال، طريقتان باستخدام sed و awk، على التوالي:
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)
ألا يوجد شيء مباشر؟هل هناك أي شيء مشابه لوظيفة Split() في Bash؟
تحديث:
يبدو أنني بحاجة إلى الاعتذار عن سؤالي الغامض عمدًا؛لم أكن مهتمًا بحل حالة استخدام محددة بقدر اهتمامي بإثارة مناقشة جيدة.لحسن الحظ، حصلت عليه!
هناك بعض التقنيات الذكية جدًا هنا.وفي النهاية، أضفت الوظائف الثلاث التالية إلى صندوق الأدوات الخاص بي.يحدث السحر في path_remove، والذي يعتمد إلى حد كبير على استخدام مارتن يورك الذكي لـ 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
لإزالة القولون زائدة.وبالنظر إلى مدى وضوح بقية حل مارتن، فأنا على استعداد تام للتعايش معه!
سؤال ذو صلة: كيف يمكنني التعامل مع عناصر PATH $ في البرامج النصية لـ Shell؟
المحلول
دقيقة مع اوك:
# 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" لإزالة هذا العنصر فقط.
تحديث لكل com.sschuberth
على الرغم من أنني أعتقد أن المساحات في أ $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[*]}"
وهنا بطانة واحدة، على الرغم من التيار قبلت و أعلى تصنيف الإجابات، لا تضيف أحرفًا غير مرئية إلى PATH ويمكنها التعامل مع المسارات التي تحتوي على مسافات:
export PATH=$(p=$(echo $PATH | tr ":" "\n" | grep -v "/cygwin/" | tr "\n" ":"); echo ${p%:})
شخصيًا، أجد أيضًا أن هذا سهل القراءة/الفهم، ولا يتضمن سوى الأوامر الشائعة بدلاً من استخدام awk.
هنا الحل الذي:
- خالص باش
- لا يستدعي عمليات أخرى (مثل '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.لا تزال هذه العناصر موجودة في حزمة bash-docs على Fedora، ويتم استخدامها في /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/}
ما هي الطريقة الأكثر أناقة لإزالة المسار من متغير PATH $ في Bash؟
ما هو أكثر أناقة من 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']
سيكون أقصر قليلاً، ويقدم نفس النتيجة المذكورة أعلاه، لكنني قلق من أن بايثون قد تفعل شيئًا ما مع متغير البيئة هذا، لذلك ربما يكون من الأفضل توصيله مباشرة من البيئة التي تهتم بها.)
وبالمثل للإزالة من النهاية:
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، الطريقة الأكثر أناقة، IMHO، هي عدم إضافتها في المقام الأول.في سطر واحد:
if ! $( echo "$PATH" | tr ":" "\n" | grep -qx "$folder" ) ; then PATH=$PATH:$folder ; fi
يمكن استبدال $folder بأي شيء، وقد يحتوي على مسافات ("/home/user/my Documents")
حل باش النقي الأكثر أناقة الذي وجدته حتى الآن:
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 من Scratch ثلاث وظائف 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 لسؤاله الأصلي.لتعميمها، أستخدم نموذجًا مكونًا من وسيطتين، مما يسمح لي بتعيين 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 ومتغيرات البيئة الأخرى بناءً على أجزاء التجميع التي تتحكم فيها، مثل موقع المترجم والمكتبات والأدوات والمكونات وما إلى ذلك.اجعل كل عنصر قابل للتكوين شيئًا يمكنك تعيينه بشكل فردي والتحقق منه ثم استخدامه بشكل مناسب في البرنامج النصي الخاص بك.
على سبيل المثال، لدي إصدار Java يستهدف WebLogic يستند إلى Maven وقد ورثته من صاحب العمل الجديد.يشتهر نص البناء بكونه هشًا، وقد أمضيت أنا وموظف جديد آخر ثلاثة أسابيع (ليس بدوام كامل، فقط هنا وهناك، ولكن لا يزال هناك عدة ساعات) في جعله يعمل على أجهزتنا.كانت الخطوة الأساسية هي أنني سيطرت على PATH حتى أعرف بالضبط أي Java، وأي Maven، وأي WebLogic تم استدعاؤه.لقد قمت بإنشاء متغيرات بيئة للإشارة إلى كل من هذه الأدوات، ثم حسبت PATH بناءً على تلك المتغيرات بالإضافة إلى عدد قليل من الأدوات الأخرى.قامت تقنيات مماثلة بترويض الإعدادات الأخرى القابلة للتكوين، حتى أنشأنا في النهاية بنية قابلة للتكرار.
بالمناسبة، لا تستخدم Maven، Java لا بأس بها، ولا تشتري WebLogic إلا إذا كنت في حاجة ماسة إلى تجميعاته (لكن بخلاف ذلك لا، لا سيما ميزاته الخاصة).
أطيب التمنيات.
كما هو الحال مع @litb، ساهمت في الإجابة على السؤال "كيف يمكنني التعامل مع عناصر PATH $ في البرامج النصية لـ Shell"، لذا فإن إجابتي الرئيسية موجودة.
وظيفة "التقسيم" في bash
ومشتقات Bourne Shell الأخرى يتم تحقيقها بدقة أكبر باستخدام $IFS
, ، الفاصل بين الحقول.على سبيل المثال، لتعيين الوسائط الموضعية ($1
, $2
, ، ...) لعناصر PATH، استخدم:
set -- $(IFS=":"; echo "$PATH")
سيعمل بشكل جيد طالما لا توجد مسافات في $PATH.إن جعل الأمر يعمل مع عناصر المسار التي تحتوي على مسافات هو تمرين غير تافه - متروك للقارئ المهتم.ربما يكون من الأسهل التعامل معها باستخدام لغة برمجة نصية مثل Perl.
لدي أيضاً سكريبت clnpath
, ، والذي أستخدمه على نطاق واسع لإعداد PATH الخاص بي.وقد وثقته في الرد على "كيفية تجنب تكرار متغير PATH في csh".
ما يجعل هذه المشكلة مزعجة هي حالات السياج بين العناصر الأولى والأخيرة.يمكن حل المشكلة بشكل أنيق عن طريق تغيير IFS واستخدام مصفوفة، لكنني لا أعرف كيفية إعادة تقديم النقطتين بمجرد تحويل المسار إلى نموذج مصفوفة.
إليك نسخة أقل أناقة قليلاً تزيل دليلاً واحدًا من $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.
السبب في زائدة ':' هو أنك تقوم بتعيين نهاية السطر، وليس الفاصل.أستخدم وحدات محدودة الموارد وأرغب في تجميع كل شيء في برنامج نصي واحد، بدون هذه الشذوذات:
path_remove () {
PATH="$(echo -n $PATH | awk -v RS=: -v ORS= '$0 != "'$1'"{print s _ $0;s=":"}')"
}