함수를 통해 전달될 때 ~를 Windows 사용자 디렉터리로 변환하는 Linux의 Windows 시스템에서 Bash용으로 무언가를 작성하려고 합니다 winpath
. 지금까지는 Windows 디렉토리를 검색하여 Unix 경로로 변환할 수 있었고 두 경로를 연결 /home/[username]/
하는 ~
데 문제가 있는 .
아래와 같이 두 가지 변수가 있습니다.
$target_path=/home/jacob/Repositories
$user_path=/mnt/c/Users/Jacob
(실제로 프로그래밍 방식으로 검색하고 있지만 차이가 없다고 생각합니다.)
그런 다음 /home/jacob
삭제 $target_path
하고 그대로 둡니다 /Repositories
.
대상은 $user_path
수정된 대상과 결합되어 $target_path
다음을 출력합니다.
/mnt/c/Users/Jacob/Repositories
이를 위해 나는 다음과 같이 합니다.
target_path=$user_path$target_path
그러나 어떤 이유에서인지 출력은 다음과 같습니다.
/RepositoriesJacob
$user_path
내가 직접 출력해도 맞고, $target_path
직접 출력해도 맞기 때문에 이것은 말이 되지 않습니다 . 그래서 두 가지를 결합하면 혼란이 생깁니다.
관련 라인은 8-20입니다.이 점(전체 코드는 아래에 붙여넣었습니다).
winpath() {
# get the Windows user path
user_path=$(/mnt/c/Windows/System32/cmd.exe /C echo %HOMEDRIVE%%HOMEPATH%)
# expand the specified path
target_path=$(readlink -f $1)
# change ~ to $user_path (WIP)
if grep -q "^/home/" <<< $target_path; then
# convert Windows-style user path to Unix-style (i.e. from C:\Users\[username] to /mnt/c/Users/[username])
temp_user_path=$(echo "$user_path" | sed -e 's|\\|/|g' -e 's|^\([A-Za-z]\)\:/\(.*\)|/mnt/\L\1\E/\2|')
# remove /home/[username]/ from $target_path
target_path=$(echo "$target_path" | sed -e 's|^/home/\(.*\)/\(.*\)|/\2|')
# output $temp_user_path for debugging
echo $temp_user_path # correctly outputs
# output $target_path for debugging
echo $target_path # correctly outputs
# combine the variables
echo $temp_user_path$target_path # DOES NOT correctly output (?)
fi
# check if a Windows path is getting parsed
if grep -q "^/mnt/[a-z]/" <<< $target_path; then
# swap /mnt/[a-z]/ with [A-Z]:/ and / with \
echo $(echo "$target_path" | sed -e 's|^\(/mnt/\([a-z]\)/\)\(.*\)|\U\2:\\\E\3|' -e 's|/|\\|g')
else
# return the user's home directory if a Unix path was parsed
echo $user_path
fi
}
편집: 좋아요, 이상하네요... Mac에서 시도해 보니 잘 작동합니다. 어쩌면 이것은 WSL 버그일까요?
편집 2: 추가 테스트를 거친 결과 이는 두 출력을 결합하는 것과 관련이 있는 것으로 보입니다 sed
. 문자열을 변수로 입력하고 결합해 보면 잘 작동합니다. 잘.
답변1
예, 추가 캐리지 리턴이 문제입니다.
프로세스 대체는 프로세스의 출력에서 마지막 개행 문자를 제거하지만 cmd.exe
CR-LF 쌍이 출력되는 경우 캐리지 리턴 문자는 끝에 유지됩니다 user_path
. 인쇄할 때 CR은 출력이 인쇄할 때 줄의 시작 부분으로 돌아가도록 합니다. Repositories
길이가 동일 /mnt/c/Users
하므로 아래 슬래시는 논리적으로 정렬됩니다(단어가 끊어진 것처럼 보이는 경우와 반대).
를 사용하여 Bash에서 후행 CR을 제거할 수 있습니다 ${user_path%$'\r'}
. ( ${var%pattern}
변수에서 패턴과 일치하는 접미사 제거)
's|^/home/\(.*\)/\(.*\)|/\2|'
또한 두 번째 sed( )가 너무 열정적이라고 생각합니다 . 첫 번째 .*
는 일치할 수 있는 가장 긴 문자열과 일치하므로 /home/user/foo/bar
대신 /bar
매개 /foo/bar
변수 확장을 통해 이 작업을 수행할 수도 있습니다 ${target_path#/home/*/}
. 1의 경우 #
가장 짧은 일치 접두사를 제거합니다 . .
답변2
@steeldriver 님의 도움 덕분에 이 문제를 해결할 수 있었습니다! 이상하게도 CMD는 한 줄만 출력하지만 이는 Windows 줄 끝 문제입니다. 해결책은 CMD 출력을 Unix 스타일로 변환하여 문제를 해결하는 것이었습니다! 이것이 내 최종 코드입니다.
winpath() {
# get the Windows user path, convert to Unix line endings
user_path=$(echo "$(/mnt/c/Windows/System32/cmd.exe /C echo %HOMEDRIVE%%HOMEPATH%)" | tr -d "\r")
# expand the specified path
target_path=$(readlink -f $1)
# change ~ to $user_path
if grep -q "^/home/" <<< $target_path; then
temp_user_path=$(echo "$user_path" | sed -e 's|\\|/|g' -e 's|^\([A-Za-z]\)\:/\(.*\)|/mnt/\L\1\E/\2|' -e 's|^M$||')
# if there was something after ~, add it to the end of the $user_path
if grep -q "^/home/\(.*\)/\(.*\)" <<< $target_path; then
target_path=$temp_user_path$(echo "$target_path" | sed -e 's|^/home/*/\(.*\)|/\2|')
# if there was nothing after ~, $target_path is $user_path
else
target_path=$temp_user_path
fi
fi
# check if a Windows path is getting parsed
if grep -q "^/mnt/[a-z]" <<< $target_path; then
# swap /mnt/[a-z] with [A-Z]: and / with \
echo $(echo "$target_path" | sed -e 's|^\(/mnt/\([a-z]\)\)\(.*\)|\U\2:\E\3|' -e 's|/|\\|g')
else
# return the user's home directory if a Unix path was parsed
echo $user_path
fi
}