Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException
вообще.
См. также: A хороший список лучших практик
Я бы добавил, очень важно, хорошо использовать модификатор final
. Использование "окончательной" модификатор, когда это применимо в Java
Сводка:
final
для обеспечения хорошей инициализации. @NotNull
и @Nullable
if("knownObject".equals(unknownObject)
valueOf()
поверх toString (). StringUtils
StringUtils.isEmpty(null)
. Обращение к предлагаемому решению от dmckee:
export
как эквивалентные установке (или даже создание) глобальная переменная - что-то, чтобы избежаться, когда это возможно. replace-path PATH $PATH /usr
' делать, но это не делает то, что я ожидал бы. Рассматривают значение ПУТИ, которое начинается содержащий:
.
/Users/jleffler/bin
/usr/local/postgresql/bin
/usr/local/mysql/bin
/Users/jleffler/perl/v5.10.0/bin
/usr/local/bin
/usr/bin
/bin
/sw/bin
/usr/sbin
/sbin
результат я добрался (от' replace-path PATH $PATH /usr
'):
.
/Users/jleffler/bin
/local/postgresql/bin
/local/mysql/bin
/Users/jleffler/perl/v5.10.0/bin
/local/bin
/bin
/bin
/sw/bin
/sbin
/sbin
я ожидал бы возвращать свой первоначальный тракт, так как/usr не появляется как (полный) элемент пути, только как часть элемента пути.
Это может быть зафиксировано в [1 116] путем изменения одного из sed
команды:
export $path=$(echo -n $list | tr ":" "\n" | sed "s:^$removestr\$:$replacestr:" |
tr "\n" ":" | sed "s|::|:|g")
я использовал ':' вместо '|' для разделения частей замены с тех пор '|' мог (в теории), появляются в компоненте контура, тогда как по определению ПУТИ, двоеточие не может. Я замечаю, что второе sed
могло устранить текущий каталог с середины ПУТИ. Таким образом, законное (хотя извращенный) значение ПУТИ могло быть:
PATH=/bin::/usr/local/bin
После обработки, текущий каталог больше не был бы на ПУТИ.
А подобное изменение для привязки соответствия является соответствующим в [1 119]:
export $target=$(echo -n $list | tr ":" "\n" | grep -m 1 "^$pat\$")
я отмечаю мимоходом, что grep -m 1
не является стандартным (это - расширение GNU, также доступное на MacOS X). И, действительно, -n
опция для [1 122] также нестандартна; Вы были бы более обеспечены просто удаление запаздывающего двоеточия, которое добавляется на основании преобразования новой строки от эха в двоеточие. Так как path-element-by-pattern используется только однажды, имеет нежелательные побочные эффекты (он ударяет экспортируемую переменную любого существования ранее, названную $removestr
), он может быть заменен разумно ее телом. Это, наряду с более свободным использованием кавычек для предотвращения проблем с пробелами или нежелательным расширением имени файла, приводит к:
# path_tools.bash
#
# A set of tools for manipulating ":" separated lists like the
# canonical $PATH variable.
#
# /bin/sh compatibility can probably be regained by replacing $( )
# style command expansion with ` ` style
###############################################################################
# Usage:
#
# To remove a path:
# replace_path PATH $PATH /exact/path/to/remove
# replace_path_pattern PATH $PATH <grep pattern for target path>
#
# To replace a path:
# replace_path PATH $PATH /exact/path/to/remove /replacement/path
# replace_path_pattern PATH $PATH <target pattern> /replacement/path
#
###############################################################################
# Remove or replace an element of $1
#
# $1 name of the shell variable to set (e.g. PATH)
# $2 a ":" delimited list to work from (e.g. $PATH)
# $3 the precise string to be removed/replaced
# $4 the replacement string (use "" for removal)
function replace_path () {
path=$1
list=$2
remove=$3
replace=$4 # Allowed to be empty or unset
export $path=$(echo "$list" | tr ":" "\n" | sed "s:^$remove\$:$replace:" |
tr "\n" ":" | sed 's|:$||')
}
# Remove or replace an element of $1
#
# $1 name of the shell variable to set (e.g. PATH)
# $2 a ":" delimited list to work from (e.g. $PATH)
# $3 a grep pattern identifying the element to be removed/replaced
# $4 the replacement string (use "" for removal)
function replace_path_pattern () {
path=$1
list=$2
removepat=$3
replacestr=$4 # Allowed to be empty or unset
removestr=$(echo "$list" | tr ":" "\n" | grep -m 1 "^$removepat\$")
replace_path "$path" "$list" "$removestr" "$replacestr"
}
у меня есть сценарий Perl, названный echopath
, который я нахожу полезными при отладке проблем с подобными PATH переменными:
#!/usr/bin/perl -w
#
# "@(#)$Id: echopath.pl,v 1.7 1998/09/15 03:16:36 jleffler Exp $"
#
# Print the components of a PATH variable one per line.
# If there are no colons in the arguments, assume that they are
# the names of environment variables.
@ARGV = $ENV{PATH} unless @ARGV;
foreach $arg (@ARGV)
{
$var = $arg;
$var = $ENV{$arg} if $arg =~ /^[A-Za-z_][A-Za-z_0-9]*$/;
$var = $arg unless $var;
@lst = split /:/, $var;
foreach $val (@lst)
{
print "$val\n";
}
}
, Когда я выполняю измененное решение на тестовом коде ниже:
echo
xpath=$PATH
replace_path xpath $xpath /usr
echopath $xpath
echo
xpath=$PATH
replace_path_pattern xpath $xpath /usr/bin /work/bin
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath $xpath "/usr/.*/bin" /work/bin
echopath xpath
вывод:
.
/Users/jleffler/bin
/usr/local/postgresql/bin
/usr/local/mysql/bin
/Users/jleffler/perl/v5.10.0/bin
/usr/local/bin
/usr/bin
/bin
/sw/bin
/usr/sbin
/sbin
.
/Users/jleffler/bin
/usr/local/postgresql/bin
/usr/local/mysql/bin
/Users/jleffler/perl/v5.10.0/bin
/usr/local/bin
/work/bin
/bin
/sw/bin
/usr/sbin
/sbin
.
/Users/jleffler/bin
/work/bin
/usr/local/mysql/bin
/Users/jleffler/perl/v5.10.0/bin
/usr/local/bin
/usr/bin
/bin
/sw/bin
/usr/sbin
/sbin
Это выглядит корректным мне - по крайней мере, для моего определения того, какова проблема.
я отмечаю, что echopath LD_LIBRARY_PATH
оценивает $LD_LIBRARY_PATH
. Было бы хорошо, если бы Ваши функции смогли сделать это, таким образом, пользователь мог ввести:
replace_path PATH /usr/bin /work/bin
, Который может быть сделан при помощи:
list=$(eval echo ' Это приводит к этому пересмотру кода:
# path_tools.bash
#
# A set of tools for manipulating ":" separated lists like the
# canonical $PATH variable.
#
# /bin/sh compatibility can probably be regained by replacing $( )
# style command expansion with ` ` style
###############################################################################
# Usage:
#
# To remove a path:
# replace_path PATH /exact/path/to/remove
# replace_path_pattern PATH <grep pattern for target path>
#
# To replace a path:
# replace_path PATH /exact/path/to/remove /replacement/path
# replace_path_pattern PATH <target pattern> /replacement/path
#
###############################################################################
# Remove or replace an element of $1
#
# $1 name of the shell variable to set (e.g. PATH)
# $2 the precise string to be removed/replaced
# $3 the replacement string (use "" for removal)
function replace_path () {
path=$1
list=$(eval echo ' следующий пересмотренный тест теперь работает также:
echo
xpath=$PATH
replace_path xpath /usr
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath /usr/bin /work/bin
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath "/usr/.*/bin" /work/bin
echopath xpath
Это производит тот же вывод как прежде.
$path)
remove=$2
replace=$3 # Allowed to be empty or unset
export $path=$(echo "$list" | tr ":" "\n" | sed "s:^$remove\$:$replace:" |
tr "\n" ":" | sed 's|:$||')
}
# Remove or replace an element of $1
#
# $1 name of the shell variable to set (e.g. PATH)
# $2 a grep pattern identifying the element to be removed/replaced
# $3 the replacement string (use "" for removal)
function replace_path_pattern () {
path=$1
list=$(eval echo ' следующий пересмотренный тест теперь работает также:
echo
xpath=$PATH
replace_path xpath /usr
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath /usr/bin /work/bin
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath "/usr/.*/bin" /work/bin
echopath xpath
Это производит тот же вывод как прежде.
$path)
removepat=$2
replacestr=$3 # Allowed to be empty or unset
removestr=$(echo "$list" | tr ":" "\n" | grep -m 1 "^$removepat\$")
replace_path "$path" "$removestr" "$replacestr"
}
следующий пересмотренный тест теперь работает также:
echo
xpath=$PATH
replace_path xpath /usr
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath /usr/bin /work/bin
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath "/usr/.*/bin" /work/bin
echopath xpath
Это производит тот же вывод как прежде.
$path)
Это приводит к этому пересмотру кода:
# path_tools.bash
#
# A set of tools for manipulating ":" separated lists like the
# canonical $PATH variable.
#
# /bin/sh compatibility can probably be regained by replacing $( )
# style command expansion with ` ` style
###############################################################################
# Usage:
#
# To remove a path:
# replace_path PATH /exact/path/to/remove
# replace_path_pattern PATH <grep pattern for target path>
#
# To replace a path:
# replace_path PATH /exact/path/to/remove /replacement/path
# replace_path_pattern PATH <target pattern> /replacement/path
#
###############################################################################
# Remove or replace an element of $1
#
# $1 name of the shell variable to set (e.g. PATH)
# $2 the precise string to be removed/replaced
# $3 the replacement string (use "" for removal)
function replace_path () {
path=$1
list=$(eval echo ' следующий пересмотренный тест теперь работает также:
echo
xpath=$PATH
replace_path xpath /usr
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath /usr/bin /work/bin
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath "/usr/.*/bin" /work/bin
echopath xpath
Это производит тот же вывод как прежде.
$path)
remove=$2
replace=$3 # Allowed to be empty or unset
export $path=$(echo "$list" | tr ":" "\n" | sed "s:^$remove\$:$replace:" |
tr "\n" ":" | sed 's|:$||')
}
# Remove or replace an element of $1
#
# $1 name of the shell variable to set (e.g. PATH)
# $2 a grep pattern identifying the element to be removed/replaced
# $3 the replacement string (use "" for removal)
function replace_path_pattern () {
path=$1
list=$(eval echo ' следующий пересмотренный тест теперь работает также:
echo
xpath=$PATH
replace_path xpath /usr
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath /usr/bin /work/bin
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath "/usr/.*/bin" /work/bin
echopath xpath
Это производит тот же вывод как прежде.
$path)
removepat=$2
replacestr=$3 # Allowed to be empty or unset
removestr=$(echo "$list" | tr ":" "\n" | grep -m 1 "^$removepat\$")
replace_path "$path" "$removestr" "$replacestr"
}
следующий пересмотренный тест теперь работает также:
echo
xpath=$PATH
replace_path xpath /usr
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath /usr/bin /work/bin
echopath xpath
echo
xpath=$PATH
replace_path_pattern xpath "/usr/.*/bin" /work/bin
echopath xpath
Это производит тот же вывод как прежде.
Перерегистрация моего ответа на , Что самый изящный путь состоит в том, чтобы удалить путь из переменной $PATH в Bash? :
#!/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=$(IFS=':';t=($PATH);unset IFS;t=(${t[@]%%*usr*});IFS=':';echo "${t[*]}");
Для удаления элемента можно использовать sed:
#!/bin/bash
NEW_PATH=$(echo -n $PATH | tr ":" "\n" | sed "/foo/d" | tr "\n" ":")
export PATH=$NEW_PATH
удалит пути, которые содержат "нечто" от пути.
Вы могли также использовать sed для вставки новой строки прежде или после данной строки.
Редактирование: можно удалить дубликаты путем передачи по каналу через вид и uniq:
echo -n $PATH | tr ":" "\n" | sort | uniq -c | sed -n "/ 1 / s/.*1 \(.*\)/\1/p" | sed "/foo/d" | tr "\n" ":"
Существует несколько соответствующих программ в ответах на" , Как удержаться от дублирования переменной пути в csh". Они концентрируются больше на обеспечении, что нет никаких повторных элементов, но сценарий, который я предоставляю, может использоваться как:
export PATH=$(clnpath $head_dirs:$PATH:$tail_dirs $remove_dirs)
Принятие у Вас есть один или несколько каталогов в $head_dirs и один или несколько каталогов в $tail_dirs и один или несколько каталогов в $remove_dirs, тогда это использует оболочку для конкатенации головы, текущей и части хвоста в крупное значение, и затем удаляет каждый из каталогов, перечисленных в $remove_dirs от результата (не ошибка, если они не существуют), а также устранение вторых и последующих случаев любого каталога в пути.
Это не обращается к компонентам контура помещения в определенное положение (кроме вначале или конец и те только косвенно). Письменным образом определение, где Вы хотите добавить новый элемент, или какой элемент Вы хотите заменить, грязно.
Просто примечание, которые колотят себя, может сделать поиск и замену. Это может сделать все нормальное "однажды или все", случаи [в] чувствительных опциях Вы ожидали бы.
Из страницы справочника:
$ {параметр/шаблон/строка}
шаблон расширен для создания шаблона так же, как в расширении пути. Параметр расширен, и самое долгое соответствие шаблона против его значения заменяется строкой. Если Ipattern начинается/, все соответствия шаблона заменяются строкой. Обычно только первое соответствие заменяется. Если шаблон начинается с #, он должен соответствовать в начале расширенного значения параметра. Если шаблон начинается с %, он должен соответствовать в конце расширенного значения параметра. Если строка является пустой, соответствия шаблона удалены, и / после шаблона может быть опущен. Если параметр или *, операция замены применяется к каждому позиционному параметру в свою очередь, и расширение является результирующим списком. Если параметр является переменной типа массив, преобразованной в нижний индекс с или *, операция замены применяется к каждому члену массива в свою очередь, и расширение является результирующим списком.
можно также сделать полевое разделение путем установки $IFS (разделитель поля ввода) к желаемому разделителю.
Хорошо, благодаря всем респондентам. Я подготовил инкапсулированную версию ответа флорина. Первая передача похожа на это:
# path_tools.bash
#
# A set of tools for manipulating ":" separated lists like the
# canonical $PATH variable.
#
# /bin/sh compatibility can probably be regained by replacing $( )
# style command expansion with ` ` style
###############################################################################
# Usage:
#
# To remove a path:
# replace-path PATH $PATH /exact/path/to/remove
# replace-path-pattern PATH $PATH <grep pattern for target path>
#
# To replace a path:
# replace-path PATH $PATH /exact/path/to/remove /replacement/path
# replace-path-pattern PATH $PATH <target pattern> /replacement/path
#
###############################################################################
# Finds the _first_ list element matching $2
#
# $1 name of a shell variable to be set
# $2 name of a variable with a path-like structure
# $3 a grep pattern to match the desired element of $1
function path-element-by-pattern (){
target=$1;
list=$2;
pat=$3;
export $target=$(echo -n $list | tr ":" "\n" | grep -m 1 $pat);
return
}
# Removes or replaces an element of $1
#
# $1 name of the shell variable to set (i.e. PATH)
# $2 a ":" delimited list to work from (i.e. $PATH)
# $2 the precise string to be removed/replaced
# $3 the replacement string (use "" for removal)
function replace-path () {
path=$1;
list=$2;
removestr=$3;
replacestr=$4; # Allowed to be ""
export $path=$(echo -n $list | tr ":" "\n" | sed "s|$removestr|$replacestr|" | tr "\n" ":" | sed "s|::|:|g");
unset removestr
return
}
# Removes or replaces an element of $1
#
# $1 name of the shell variable to set (i.e. PATH)
# $2 a ":" delimited list to work from (i.e. $PATH)
# $2 a grep pattern identifying the element to be removed/replaced
# $3 the replacement string (use "" for removal)
function replace-path-pattern () {
path=$1;
list=$2;
removepat=$3;
replacestr=$4; # Allowed to be ""
path-element-by-pattern removestr $list $removepat;
replace-path $path $list $removestr $replacestr;
}
Все еще обнаружение ошибок потребностей во всех функциях, и я должен, вероятно, всунуть повторное решение для пути, в то время как я в нем.
Вы используете его путем выполнения . /include/path/path_tools.bash
в рабочем сценарии и обращения replace-path*
функции.
я все еще открыт для новых и/или лучших ответов.
Это - легкое использование awk.
{
for(i=1;i<=NF;i++)
if($i == REM)
if(REP)
print REP;
else
continue;
else
print $i;
}
Запускается, она с помощью [1 114]
function path_repl {
echo $PATH | awk -F: -f rem.awk REM="$1" REP="$2" | paste -sd:
}
$ echo $PATH
/bin:/usr/bin:/home/js/usr/bin
$ path_repl /bin /baz
/baz:/usr/bin:/home/js/usr/bin
$ path_repl /bin
/usr/bin:/home/js/usr/bin
, Вставляет в данном положении. По умолчанию это добавляет в конце.
{
if(IDX < 1) IDX = NF + IDX + 1
for(i = 1; i <= NF; i++) {
if(IDX == i)
print REP
print $i
}
if(IDX == NF + 1)
print REP
}
Запускаются, это с помощью [1 116]
function path_app {
echo $PATH | awk -F: -f app.awk REP="$1" IDX="$2" | paste -sd:
}
$ echo $PATH
/bin:/usr/bin:/home/js/usr/bin
$ path_app /baz 0
/bin:/usr/bin:/home/js/usr/bin:/baz
$ path_app /baz -1
/bin:/usr/bin:/baz:/home/js/usr/bin
$ path_app /baz 1
/baz:/bin:/usr/bin:/home/js/usr/bin
, Этот сохраняет первые вхождения.
{
for(i = 1; i <= NF; i++) {
if(!used[$i]) {
print $i
used[$i] = 1
}
}
}
Запускают его как это:
echo $PATH | awk -F: -f rem_dup.awk | paste -sd:
, следующее распечатает сообщение об ошибке для всех записей, которые не являются существующими в файловой системе и возвращают ненулевое значение.
echo -n $PATH | xargs -d: stat -c %n
, Чтобы просто проверить, являются ли все элементы путями и получают код возврата, можно также использовать test
:
echo -n $PATH | xargs -d: -n1 test -d
Первой вещью появиться в мою голову для изменения просто части строки является sed замена.
пример: если $PATH эха => "/usr/pkg/bin:/usr/bin:/bin:/usr/pkg/games:/usr/pkg/X11R6/bin" затем для изменения "/usr/bin" на "/usr/local/bin" мог бы быть сделан как это:
## производит файл
стандартного вывода ## "=", символ используется вместо наклонной черты (" / "), так как это было бы грязно, # альтернативный символ заключения в кавычки должно быть маловероятным в ПУТИ
## символ разделителя пути ":" и удален и повторно добавлен здесь, # мог бы хотеть дополнительное двоеточие после последнего пути
$PATH эха | sed '=/usr/bin: =/usr/local/bin: ='
Это решение заменяет весь элемент пути, так могло бы быть избыточным, если новый элемент подобен.
, Если новый ПУТЬ '-s не является динамичным, но всегда в некотором постоянном наборе, Вы могли бы сохранить те в переменной и присвоиться по мере необходимости:
$TEMP_PATH_1 PATH=; # управляет...; \n PATH= $TEMP_PATH_2; # управляет и т.д....;
не Мог бы быть тем, что Вы думали. некоторые соответствующие команды на ударе/Unix были бы:
pushd popd CD ls #, возможно, l-1A для отдельного столбца; найдите grep, какой # мог подтвердить, что файл - то, где Вы думаете, что это прибыло из; огибающий тип
.. и все это и больше имеют [приблизительно 111] влияние на ПУТЬ или каталоги в целом. Текст, изменяющий часть, мог быть сделан любое количество путей!
Независимо от того, что выбранное решение имело бы 4 части:
1) выбирают путь, как это, 2) декодируют путь для нахождения изменений необходимости части 3) determing, какие изменения нуждаются/интегрируются те изменения 4) интеграция/установка проверки/финала переменная