up
내가 있는 디렉토리 위의 지정된 디렉토리로 쉽게 이동할 수 있게 해주는 (내 bashrc의 함수로)라는 명령이 있습니다 . 이 명령은 잘 작동하지만 bash 탭 완성 기능을 추가하면 훨씬 더 유용해집니다. 현재 경로의 디렉터리를 식별하고 완료를 위해 나열하는 완료 스크립트를 작성했습니다. 내가 겪고 있는 문제는 디렉토리를 변경할 때마다 완료 스크립트가 다시 로드되지 않는 것 같아서 여전히 이전 디렉토리에 있는 것처럼 결과가 나온다는 것입니다. 명령 기능을 up
추가하여 명령을 수정할 수 있었지만 exec bash
임의의 디렉터리 변경 명령으로 이를 수행할 수 있는지 잘 모르겠습니다. exec bash
for while the command is running 을 추가하면 이 작업을 수행할 수 있을 것 같지만 cd
이를 수행하는 가장 좋은 방법이 무엇인지 잘 모르겠습니다.
예를 들어:
터미널을 열면 홈 디렉터리에 있습니다.
~$
이것을 입력하면 다음과 같은 결과 up <TAB><TAB>
가 나타납니다.
~$ up
username home
여기서 사용자 이름은 내 컴퓨터의 사용자 이름입니다. 그런 다음 CD를 입력 dir1/dir2/
하고 다음을 up <TAB><TAB>
얻었습니다.
~/dir1/dir2$ up
username home
다시 말하지만, 디렉토리를 변경했지만.
내 완료 스크립트 및 up 스크립트의 코드는 다음과 같습니다.
스크립트를 완성하세요:
#/usr/bin/env bash
LS=$(echo $PWD)
LSARRAY=${LS//\// }
complete -W "$LSARRAY" up
위로 명령(.bashrc에서)
LS=$(echo $PWD)
LSARRAY=(${LS//\// })
i=1
if [[ $LS == *$1/* ]]; then
FIND=$1
if [[ $1 == */* ]]; then
ARR=(${FIND//\// })
FIND=${ARR[${#ARR[@]}-1]}
fi
while [ "${LSARRAY[${#LSARRAY[@]}-$i]}" != "$FIND" ] && [ $i != ${#LSARRAY[@]} ]; do
cd ../
i=$(($i+1))
done
exec bash
else
echo "Did not find directory $1"
fi
답변1
다음은 다음을 시도하는 함수 up
(프로그래밍 가능 완료 대응 포함)의 대체 구현입니다.
- 임의의 경로를 사용하십시오(공백 문자 및 개행 문자 포함).
- 변수를 변경하지 마십시오
IFS
. 이는 다음 경우에 유용합니다.올바른 회복; - 일부 특수 디렉토리를 명시적으로 처리합니다(
.
여기서는..
임의의 방식으로 처리되므로 원하는 대로 코드를 조정해야 할 수도 있습니다).
기능 up
:
up () {
local path=$PWD
case $1 in
(''|'..')
cd ..; return ;;
(.)
cd .; return ;;
(/)
cd /; return ;;
(*/*)
printf '"%s" %s\n' "$1" 'contains forward slashes, up will not work' >&2
return 1 ;;
esac
if [[ $path != /* ]]; then
printf '%s\n' 'PWD is not an absolute path, up will not work' >&2
return 1
fi
until [[ $path = / ]]; do
path=${path%/*}
path=${path:-/}
if [[ ${path%"$1"} != "$path" ]] # You may add && [[ -d ${path%"$1"} ]] to
# make "up oo" fail when you are in `/foo/bar`,
# while "up foo" would succeed anyway
then
cd -- "$path"
return
fi
done
printf '%s "%s" %s\n' 'Directory' "$1" 'not found' >&2
return 1
}
완성 _up
기능 및 설명( complete
명령):
_up () {
local cur last path
declare -A ancestors
cur=${COMP_WORDS[$COMP_CWORD]}
path=$PWD
if [[ $path != /* ]]; then
return 1
fi
until [[ -z $path ]]; do
path=${path%/*}
last=${path##*/}
last=${last:-/}
if [[ $last == "${cur}"* ]]; then
ancestors+=( ["$last"]= )
fi
done
COMPREPLY=( "${!ancestors[@]}" )
return
}
complete -o nospace -o filenames -F _up up
두 코드 조각 모두 에 배치되어야 합니다 .bashrc
.배쉬 완료완성 기능과 사양을 또는 에 저장하는 것을 선호할 수도 있습니다 $XDG_DATA_HOME/bash-completion
( 자세한 내용은 잉크 페이지의 FAQ 참조).~/.local/share/bash-completion
~/.bash_completion
슬래시가 포함된 인수는 의도적으로 제외됩니다. 그렇지 않으면 (제 생각에는) foo/bar
주의를 기울여야 하기 때문입니다 foo///bar/./../baz
(예: 어떤 형태의 정규화 수행).
연관 배열( declare -A
)을 사용하려면 Bash >= 4.0이 필요합니다.
답변2
LS
문제는 변수 평가가 LSARRAY
한 번만 발생하므로 항상 up
완성이 정의된 상위 폴더를 사용하여 명령을 완료한다는 것입니다.PWD
상위 폴더를 동적으로 추출하려면 완성 함수를 만들어야 합니다. 이렇게 하면 실제 전류를 기반으로 up 명령을 완료하려고 할 때 LS
마다 및 변수가 평가됩니다 .LSARRAY
PWD
_complete_up()
{
local cur=${COMP_WORDS[COMP_CWORD]}
local LS=$(echo $PWD)
local LSARRAY=${LS//\// }
COMPREPLY=( $(compgen -W "${LSARRAY}" -- $cur) )
return 0
}
complete -F _complete_up up
답변3
다음을 수행할 수 있습니다.
_up () {
local oldIFS="$IFS" LS="${PWD%/*}"
IFS='/
'
if [ -n "$2" ]; then
COMPREPLY=($(compgen -W "${LS#/}" "$2"))
else
COMPREPLY=(${LS#/})
fi
IFS="$oldIFS"
}
complete -F _up up
up () {
local oldIFS="$IFS" i=1 LSARRAY LS="$PWD" FIND ARR
IFS='/
'
LSARRAY=(${PWD#/})
if [[ $LS == */$1/* ]]; then
FIND=$1
while [ "${LSARRAY[${#LSARRAY[@]}-$i]}" != "$FIND" ] && [ $i != ${#LSARRAY[@]} ]; do
cd ..
i=$(($i+1))
done
else
echo "Did not find directory '$1'"
fi
IFS="$oldIFS"
}
주요 문제는 (이전 답변에서 언급했듯이) 완료 가능성이 동적으로 생성되지 않는다는 것입니다.
또한 코드는 디렉터리 이름의 공백과 함께 작동하지 않습니다. 내 것은 디렉토리 이름에 개행 문자를 지원하지 않습니다.
또한 말이 안 되기 때문에 선택 목록에서 현재 디렉터리를 제거했습니다.
디렉터리 이름은 절대 포함될 수 없기 때문에 무엇을 if [[ $1 == */* ]]
해야 하는지 이해하지 못해서 제거했습니다.if [[ $FIND == */* ]]
/