POSIX 쉘 스크립트에서 $@ 배열을 수정하는 방법이 있습니까?

POSIX 쉘 스크립트에서 $@ 배열을 수정하는 방법이 있습니까?

readlink심볼릭 링크를 사용하여 일반 파일을 얻는 방법을 알 수도 있습니다 . $@내 함수에 전달된 심볼릭 링크를 다음과 같이 바꾸는 매우 기본적인 아이디어가 있습니다 .

for file in "$@"; do
    [ -L "$file" ] && file=$(readlink -f "$file")
done

예를 들면 SymLink 입니다 /etc/os-release -> ../usr/lib/os-release.

하지만 이렇게 하면:

set -- '/etc/os-release'; for file in "$@"; do [ -L "$file" ] && file=$(readlink -f "$file"); done; echo "$@"

여전히 원래 SymLink 경로를 얻을 수 있는데 이는 실망스럽습니다. 직접 수정하고 싶은데 $@불가능하다면 해결책이 없을까요?

답변1

원본 코드:

for file in "$@"; do
    [ -L "$file" ] && file=$(readlink -f -- "$file")
done

문제는 file루프 내의 설정이 위치 인수 목록의 내용에 영향을 미치지 않는다는 것입니다.

대신에 다음을 사용하고 싶을 수도 있습니다.

for file in "$@"; do
    [ -L "$file" ] && file=$(readlink -f -- "$file")
    set -- "$@" "$file"
    shift
done

이제 항목을 처음부터 하나씩 제거 "$@"하고 잠재적으로 수정된 항목을 목록 뒤쪽에 추가하겠습니다. 루프 $@for수정은 루프가 항상 정적 목록을 반복하기 $@때문에 문제가 되지 않습니다 for. 즉, 반복된 목록은 루프 시작 시 한 번만 평가됩니다.

아래 루프와 마찬가지로 위 루프는 각 반복마다 위치 매개변수의 전체 목록을 재설정합니다. 하나를 위해거대한파일 이름 목록이 너무 빨리 느려질 수 있습니다. 쉘에 배열이 있는 경우,스티븐 키트의 답변작업 속도를 높이는 방법을 보여줍니다.

루프는 약간 더 짧은 형식( readlink각 요소마다 호출됨)으로 작성할 수도 있습니다.

for dummy do
    set -- "$@" "$(readlink -f -- "$1")"
    shift
done

readlink이것은 POSIX 유틸리티가 아니더라도 귀하의 질문에 따라 사용됩니다 .

참고로 출력된다면readlink 하나 이상의 줄 바꿈으로 끝납니다(출력의 마지막 줄을 종료하기 위해 추가된 내용을 제외하고) 제거됩니다. 이는 명령 대체의 결과입니다. 이것이 문제인 경우 명령 대체에 후행 문자를 인위적으로 추가하고 mosvy제안된 대로 제거하십시오.댓글에서:

for file do
    [ -L "$file" ] && file=$(readlink -f -- "$file"; echo x)
    set -- "$@" "${file%x}"
    shift
done

답변2

POSIX 명령 은 둘 다 및 readlink가 아닙니다 . POSIX 명령줄 도구 상자에는 유사한 API가 realpath없습니다 . 여기에서는 유사한 기능과 해당 수정자가 내장되어 있는 이를 realpath()대신 사용할 수 있습니다 readlink(호환되지 않는 다른 구현이 있음) . 스크립트 에서 :zshrealpath():Psh

eval "set -- $(zsh -c 'print -r ${(qq)argv:P}' zsh "$@")"

zsh스크립트를 먼저 작성할 수도 있지만 다음과 같아야 합니다.

argv=($argv:P)

아니면 python3zsh보다 더 유용합니까?

eval "set -- $(
  LC_ALL=C python3 -c '
import sys, os, shlex
print(" ".join(map(shlex.quote, map(os.path.realpath, sys.argv[1:]))))' "$@")"

관련 정보