![POSIX 쉘 스크립트에서 $@ 배열을 수정하는 방법이 있습니까?](https://rvso.com/image/168778/POSIX%20%EC%89%98%20%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%97%90%EC%84%9C%20%24%40%20%EB%B0%B0%EC%97%B4%EC%9D%84%20%EC%88%98%EC%A0%95%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95%EC%9D%B4%20%EC%9E%88%EC%8A%B5%EB%8B%88%EA%B9%8C%3F.png)
readlink
SymLinks에서 일반 파일을 가져오는 방법을 알고 있을 수도 있습니다 . 나는 $@
다음과 같이 내 함수에 전달된 SymLink를 대체하는 매우 기본적인 아이디어를 가지고 있었습니다 .
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
도 마찬가지 입니다. realpath
POSIX 명령줄 도구 상자에는 realpath()
-like API가 없습니다. 여기서는 (다른 호환되지 않는 구현이 있음) 대신 해당 수정자와 함께 -like 기능이 내장되어 있는 것을 readlink
사용할 수 있습니다 . 스크립트 에서 :zsh
realpath()
:P
sh
eval "set -- $(zsh -c 'print -r ${(qq)argv:P}' zsh "$@")"
zsh
처음부터 다음과 같이 스크립트를 작성할 수도 있습니다 .
argv=($argv:P)
또는 python3
zsh보다 사용할 가능성이 더 높은 경우:
eval "set -- $(
LC_ALL=C python3 -c '
import sys, os, shlex
print(" ".join(map(shlex.quote, map(os.path.realpath, sys.argv[1:]))))' "$@")"