bin
때로는 변경될 수 있는 디렉토리 안에 디렉토리가 있는지 확인하려고 합니다 . 이 특별한 경우에는 Ruby의 버전 번호가 변경될 수 있습니다(예 $HOME/.gem/ruby/2.6.0/bin
: ). 지금까지 내가 한 일은 다음과 같습니다.
#!/usr/bin/env zsh
ruby_gem_home="$HOME/.gem/ruby/*/bin"
if [[ -d $ruby_gem_home ]]; then
echo "The ruby gems directory exists!"
else
echo "Ruby gems directory missing!"
fi
find
이것은 로그인 프로세스의 일부이므로 사용하고 싶지 않습니다 . 이를 달성하기 위해 내장된 zsh/bash 명령을 사용하는 가장 우아한 방법은 무엇입니까?
감사해요!
편집하다:이것이 zsh
스크립트를 위한 것임을 언급하는 것을 잊었습니다.
답변1
이 경우에는 구체적으로
디렉토리를 찾는 것은 의미가 없다고 생각합니다. 설치된 Ruby 버전과 일치하지 않는 디렉토리를 사용하는 이유는 무엇입니까? 그리고 사용자가 에서 다른 디렉토리를 구성했다면 어떻게 될까요 ~/.gemrc
?
저는 Ruby에 그다지 익숙하지 않지만 올바른 해결책은 gempath
.
ruby_gem_home=$(gem environment gempath | sed 's/:.*//')
if [ -z "$ruby_gem_home" ]; then unset ruby_gem_home; fi
zsh에서
function set_ruby_gem_home {
emulate -LR zsh
local dirs
dirs=($HOME/.gem/ruby/*/bin(NnOn))
if (($#dirs == 0)); then
unset ruby_gem_home
else
ruby_gem_home=$dirs[0]
fi
}
그만큼글로벌 한정자 N
일치하는 항목이 없는 경우 결과가 오류가 아닌 빈 배열인지 확인합니다. glob 한정자는 n
버전 On
번호를 줄여 목록을 정렬합니다. 일치하는 항목이 여러 개 있을 때 다른 항목을 선택하려면 이를 조정하세요.
배쉬에서:
function set_ruby_gem_home {
local dirs
dirs=(~/.gem/ruby/*/bin(NnOn))
if (($#dirs == 0)); then
unset ruby_gem_home
else
ruby_gem_home=$dirs[0]
fi
}
배쉬에서
function set_ruby_gem_home {
local dirs restore_options
restore_options=$(setopt +o)
shopt -s nullglob
dirs=(~/.gem/ruby/*/bin)
if (($#dirs == 0)); then
unset ruby_gem_home
else
ruby_gem_home=${dirs[${#dirs[@]}-1]}
fi
eval "$restore_options"
}
여기서는 항상 최신 버전이 아닌 경우가 많은 마지막 배열 요소를 사용합니다. 10
is sorted before 9
.
답변2
배열을 사용하고 배열의 첫 번째 요소(예: bash의 경우 [0], zsh의 경우 [1])가 디렉터리인지 확인하세요. 예 bash
:
# the trailing slash in "$HOME"/.gem/ruby/*/bin/ ensures that
# the glob matches only directories.
rubygemdirs=( "$HOME"/.gem/ruby/*/bin/ )
if [ -d "${rubygemdirs[0]}" ] ; then
echo "At least one ruby gem dir exists"
else
echo "No ruby gem dirs were found"
fi
zsh
및 에서 작업하려면 bash
먼저 현재 실행 중인 셸을 찾아야 합니다. 그러면 배열의 첫 번째 인덱스가 0
또는 인지 알 수 있습니다 1
. 또한 (N)
glob과 일치하는 항목이 없는 경우 zsh에 종료하지 말라고 지시하기 위해 glob과 함께 사용해야 하는지 여부도 결정합니다 (zsh는 glob 일치 오류 시 기본적으로 종료됩니다).
(이 시점에서 안정적으로 작동하는 스크립트를 작성하는 것이 분명해지기 시작해야 합니다.둘 다bash와 zsh는 아마도 가치 있는 것보다 더 많은 문제가 될 것입니다)
if [ -n "$BASH_VERSION" ] ; then
first_idx=0
rubygemdirs=( "$HOME"/.gem/ruby/*/bin/ )
elif [ -n "$ZSH_VERSION" ] ; then
first_idx=1
emulate sh
rubygemdirs=( "$HOME"/.gem/ruby/*/bin/ )
emulate zsh
fi
if [ -d "${rubygemdirs[$first_idx]}" ] ; then
...
필요한 경우 배열을 반복하여 요소가 특정 버전과 일치하는지 확인할 수도 있습니다. 예를 들어
for d in "${rubygemdirs[@]}" ; do
[[ $d =~ /2\.6\.0/ ]] && echo found gem dir for ruby 2.6.0
done
참고: /
정규식의 s는 문자 그대로 슬래시입니다. 에서처럼 정규식의 시작과 끝을 표시하지 않습니다 sed
.
답변3
와일드카드는 목록 컨텍스트에서만 확장됩니다. 즉, 여러 항목으로 확장될 수 있습니다. 스칼라 변수에 대한 할당에서는 스칼라 변수가 하나의 값만 보유할 수 있으므로 확장할 수 없습니다.
를 사용하면 목록 컨텍스트에서 glob이 확장할 파일 목록이 아니라 문자열을 스칼라 변수에 ruby_gem_home="$HOME/.gem/ruby/*/bin"
저장하게 됩니다 ./home/user/.gem/ruby/*/bin
$ruby_gem_home
for/select x in
zsh의 목록 컨텍스트는 리디렉션 대상( multios
켜져 있는 경우), 배열 또는 연관 배열 할당 및 기타 몇 가지 특수한 경우1 에서 간단한 명령 또는 익명 함수에 대한 인수가 될 수 있습니다 .
따라서 여기서는 익명 함수를 사용할 수 있습니다.
() {
unset ruby_gem_home
case $# in
(0) print -u2 "Ruby gems directory missing!";;
(1) print -u2 "The ruby gems directory exists!"
ruby_gem_home=$1;;
(*) print -u2 "More than one ruby gem directory, don't know which to choose!";;
esac
} ~/.gem/ruby/*/bin(N-/)
여기에는 N
오류를 보고하는 대신 일치하는 항목이 없을 때 glob이 빈 목록으로 확장되고 -/
유형의 파일로 제한되도록 glob 한정자를 추가합니다.예배 규칙서(를 사용한 심볼릭 링크 해결 후에 결정됨 -
).
Ruby gem 디렉터리가 두 개 이상 있고 버전 번호가 가장 높은 디렉터리를 선택하려면 다음을 수행하세요.
() {
unset ruby_gem_home
case $# in
(0) print -u2 "Ruby gems directory missing!";;
(1) print -u2 "The ruby gems directory exists!"
ruby_gem_home=$1;;
(*) print -ru2 "More than one ruby gem directory, picking $1!"
ruby_gem_home=$1;;
esac
} ~/.gem/ruby/*/bin(N-/nOn)
가 n
켜지고 rder가 ame 에 의해 역방향으로 바뀌 numericglobsort
므로 가장 높은 숫자를 가진 항목이 포함됩니다.On
o
n
$1
¹ 설명대로info zsh 'Conditional Expressions'
, 옵션이 켜져 있는 특별한 경우도 있는데, 이 경우 일반적으로 / 연산자와 함께 extendedglob
내부 glob을 사용할 수 있습니다 . 따라서 여기에 그러한 디렉토리가 하나 이상 있는지 확인하는 데 사용할 수 있습니다 .[[ ... ]]
-n
-z
[[ -n ~/.gem/ruby/*/bin(#qN-/) ]]