Попытайтесь использовать виртуальный рабочий стол, это находится на вкладке Graphics "winecfg".
Просто набор IFS
согласно Вам потребности и позволяют оболочке выполнить разделение слова:
IFS=':'
for dir in $PATH; do
[ -x "$dir"/"$1" ] && echo $dir
done
Это работает в bash
, dash
и ksh
, но протестированный только с последними версиями.
Очевидное решение состояло бы в том, чтобы использовать разделение слова оболочки, но остерегаться нескольких глюков:
IFS=:
set -f
for dir in $PATH; do
dir=${dir:-.}
[ -x "${dir%/}/$1" ] && printf "%s\n" "$dir"
done
Вам нужно set -f
потому что, когда переменную оставляют неупомянутой, и разделение слова и поколение имени файла (globbing) выполняются на нем, и здесь Вы только хотите разделение слова (например, в маловероятном случае, что $PATH
содержит /usr/local/*bin*
, Вы хотите это, действительно заглядывают /usr/local/*bin*
папка, не в /usr/local/bin
и /usr/local/sbin
..., и если PATH
содержит /*/*/*/../../../*/*/*/*/../../../*/*/*/*
, Вы не хотите, чтобы это снизило Вашу машину),
Пустое $PATH
компонент означает текущий каталог (.
), нет /
. $dir/$1
не было бы корректно в этом случае. Работа вокруг должна или записать $dir${dir:+/}$1
или измениться $dir
кому: .
в этом случае (который дает более полезный вывод при отображении с printf '%s\n' "$dir"
.
//foo
не обязательно то же как /foo
, итак, если /
находится в $PATH
, Вы не хотите $dir/$1
, который был бы //$1
. Следовательно ${dir%/}
разделять запаздывающую наклонную черту.
Затем существует несколько других проблем:
Для $PATH
, ":"
разделитель полей в то время как для $IFS
, это - разделитель полей (да, я знаю, S
для Разделителя, вина ksh и POSIX для стандартизации ksh поведения).
Итак, если $PATH
/usr/bin:/bin:
(который является плохой практикой, но все еще обычно находимый), который означает "/usr/bin"
, "/bin"
и ""
(то есть, текущий каталог), в то время как разделение слова оболочки (весь POSIX окружает кроме zsh
) разделит это на /usr/bin
и /bin
только.
Если $PATH
установлен, но пуст, который означает: "посмотрите в текущем каталоге только". В то время как оболочки (включая тех, которые рассматривают $IFS
как разделитель), развернет его до пустого списка.
Наконец, что не менее важно. Если $PATH
сброшен, затем это имеет особое значение, которое является: посмотрите в списке поиска системного значения по умолчанию, который, к сожалению, означает что-то другое в зависимости от того, кого (что команда) Вы спрашиваете.
$ env -u PATH bash -c 'type usbipd'
usbipd is /usr/local/sbin/usbipd
$ env -u PATH ksh -c 'type usbipd'
ksh: whence: usbipd: not found
И в основном, в Вашем сценарии, необходимо было бы предположить то, что тот путь поиска по умолчанию находится в контексте, который имеет значение для Вас.
Обратите внимание, что POSIX оставляет поведение неуказанным когда $PATH
сброшен или пуст, так не поможет Вам там. Это также означает, что то, что я сказал выше, не может относиться к некоторым прошлым, текущим или будущим системам POSIX/Unix.
Короче говоря, парсинг $PATH
попытаться узнать, куда команда была бы выполнена от, - хитрый бизнес.
Существует стандартная команда для этого, которое является command
:
ls_path=$(command -v ls)
Но то, что можно спросить: почему Вы хотите знать?
Теперь на восстановление IFS к ее значению по умолчанию:
oldIFS=$IFS
IFS=:
...
IFS=$oldIFS
будет работать на практике в большинстве случаев, но, как гарантируют, не будет работать POSIX.
Причина - это если $IFS
был ранее сброшен, что означает поведение разделения значения по умолчанию (который находится в оболочках POSIX, разделенных на пространстве, вкладке или новой строке), после тех команд, это закончится набор, но пустой (что не означает разделения).
Другая потенциальная проблема состоит в том, если Вы обобщаете тот подход и используете его в большом количестве различных функций, затем если в ...
часть выше, Вы вызываете функцию, которая делает то же самое (делает копию $IFS
в $oldIFS
), затем Вы собираетесь освободить оригинал $oldIFS
и восстановите несправедливость $IFS
.
Вместо этого Вы могли использовать подоболочки когда возможный:
(
IFS=:
...
)
# only the subshell's IFS was affected, the parent still has its own IFS
Мой подход должен установить $IFS (и поворот set -f
на или прочь) каждый раз мне нужно разделение слова (который редок), и не делайте обоих восстановлений предыдущего значения. Конечно, это не работает, если Ваш сценарий называет чужой код, который не следует той практике и принимает поведение разделения слова по умолчанию.
$PATH
был самый простой короткий пример, который я мог придумать. Разделение строки с непробельными разделителями является типичной проблемой, с которой я сталкиваюсь. Я хотел знать, как участники здесь имели дело с ним устойчивым и портативным способом.
– rahmu
08.02.2013, 14:26
set -f
избегать другого побочного эффекта отъезда переменной закрыло кавычки. Многое из этого относится к другим переменным той же формы как $MANPATH
, $LD_LIBRARY_PATH
...
– Stéphane Chazelas
08.02.2013, 14:38
${FOO:-x}
и ${FOO-x}
. Эти два эквивалентны для параметра сброса, но не пустого параметра.
– chepner
11.03.2013, 20:19
oIFS=$IFS; ${IFS+:} unset oIFS
и затем то же для восстановления: IFS=$oIFS; ${oIFS+:} unset IFS
, но существует все еще проблема, если существуют вложенные функции с помощью того приема.
– Stéphane Chazelas
11.03.2013, 23:08
Если вам нужно прочитать фиксированное количество полей в переменные, вы можете использовать этот метод:
input="age:30"
IFS=':' read -r first_field second_field <<< "$input"
echo "$first_field"
echo "$second_field"
Я нашел это на Вики Грега .
-r
говорит read
, что не следует рассматривать обратную косую черту как особую.
IFS
к ее исходным значениям по умолчанию, когда-то обработка сделана? – rahmu 08.02.2013, 13:43IFS
во временной переменной, которая позволяет мне восстанавливать IFS легко. Спасибо за ответ. – rahmu 08.02.2013, 13:53(IFS=:; for … done)
. Конечно, это полезно, только если Вам не нужно что-либо позже от того, что было установлено в цикле. – manatwork 08.02.2013, 14:00IFS
часто сбрасывается по умолчанию, который не является тем же, как являющимся пустой строкой. При восстановлении его необходимо сохранить то различие. – ruakh 08.02.2013, 22:43$IFS
сброс по умолчанию, это не имеет место в любой оболочке, которую я знаю. Всей Границе нравятся оболочки, которые я знаю, имеютIFS=$' \t\n'
в их начальной IFS (за исключениемzsh
который также имеет\0
(так как это может)), – Stéphane Chazelas 08.02.2013, 23:15