Windows에서 두 변수를 결합하면 해당 변수가 파괴됩니다.

Windows에서 두 변수를 결합하면 해당 변수가 파괴됩니다.

함수를 통해 전달될 때 ~를 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.exeCR-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
}

관련 정보