
/bin/sh
와 동일하다고 잘못 생각하는 쉘 스크립트가 많이 있습니다 . 예를 들어 shebang이 /bin/bash
있지만 (점) 대신 명령을 사용합니다.#!/bin/sh
source
.
/bin/sh
에 연결되는 Ubuntu 16을 실행 중이므로 dash
bash-isms는 지원되지 않습니다.
주기적으로 스크립트를 실행해야 합니다. 또한 가끔은 이 특정 버그를 수정하고 싶어하지 않는 원저작자로부터 업데이트해야 할 때도 있습니다. 이러한 파일을 모두 수정하는 것을 피하고 싶습니다(파일이 많고 내 것이 아니며 업데이트 후에는 모든 변경 사항이 손실됩니다). 또한 다른 스크립트가 손상될 수 있으므로 시스템 전체를 변경하는 것을 피하고 싶습니다.
/bin/sh
전역 시스템을 건드리지 않고 이러한 스크립트에 사용할 수 있는 bash를 가리키는 (임시 또는 비임시) 환경을 어떻게든 생성할 수 있는 방법이 있습니까 /bin/sh
?
답변1
나는 마운트 네임스페이스나 그와 유사한 것이 그것이 무엇인지에 대한 다른 아이디어를 가지고 다른 프로세스/사용자를 예약하는 데 사용될 수 있다고 상상합니다 /bin/sh
.
그러나 이는 해킹처럼 들리며 "시스템을 영구적으로 변경하는 것"으로 간주될 수도 있습니다. 한 줄 수정을 수행하는 것이 더 쉬울 수도 있습니다. 업데이트 프로세스의 수정 부분을 만들고 버그 보고서를 게시하고 버그의 해시뱅에 업스트림 패치를 적용합니다.
GNU의 경우 sed
이를 수정하려면 다음을 수행해야 합니다.
sed -i -e '1s,^#! */bin/sh,#!/bin/bash,' /all/the/scripts/*
답변2
/bin/sh
->가 /bin/dash
내 시스템에서처럼 시스템에서 동적으로 링크된 실행 파일인 경우 (file(1)을 사용하여 확인할 수 있음) 해킹을 사용하여 LD_PRELOAD
이를 달성할 수 있습니다.
다음과 같이 작동합니다. LD_PRELOAD
glibc __libc_start_main
(실행 파일의 함수를 호출하는 함수 )를 재정의하는 작은 동적 라이브러리를 로드한 다음 main()
동일한 인수 ( 제외 )를 사용하여 argv[0] == /bin/sh
exec를 수행합니다. 그렇지 않으면 아무 일도 일어나지 않은 것처럼 원본을 호출합니다 ./bin/bash
argv[0]
__libc_start_main
$ cat sh_is_bash.c
#define _GNU_SOURCE /* for RTLD_NEXT */
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>
int __libc_start_main(
int (*main)(int,char**,char**), int ac, char **av,
int (*init)(int,char**,char**), void (*fini)(void),
void (*rtld_fini)(void), void *stack_end)
{
typeof(__libc_start_main) *real_lsm;
if(ac > 0 && !strcmp(av[0], "/bin/sh")){
av[0] = "/bin/bash";
execv(av[0], av);
err(1, "execv %s", av[0]);
}else if(real_lsm = dlsym(RTLD_NEXT, "__libc_start_main"))
return real_lsm(main, ac, av, init, fini, rtld_fini, stack_end);
else
errx(1, "BUG: dlsym: %s", dlerror());
}
$ cc -fPIC -shared -Wall -W -Wno-parentheses sh_is_bash.c -o sh_is_bash.so -ldl
$ LD_PRELOAD=`pwd`/sh_is_bash.so program ...
Shebang이 있는 모든 스크립트는 실행하는 대신 환경 변수에 절대 경로가 포함되어 있으면 실행됩니다 #! /bin/sh
./bin/bash
/bin/sh
LD_PRELOAD
sh_is_bash.so
보기 흉하지만 시스템이나 스크립트를 크게 변경할 필요가 없고 배포 및 관리가 쉽고 특별한 권한이 필요하지 않습니다.
답변3
시스템을 손상시키지 않고도 쉽게 문제를 해결할 수 있습니다!
find . -name '*.sh' -type f -exec sed -i '1s|^#! */bin/sh|#!/bin/bash|' {} +
답변4
귀하의 경우 POSIX가 아닌 확장이 포함된 스크립트에는 관련 올바른 #!
헤더가 있어야 합니다.
#!/bin/bash
따라서 잘못된 스크립트를 모두 편집할 수 있는 방법은 없다고 생각합니다.
참고: 정말로 확신한다면 bash에 대한 임시 링크를 만들고 이름을 바꿀 수 있습니다.
cd /bin
ln -s bash nsh
mv nsh sh
원자적으로 작업 하므로 mv
항상 작업이 보장됩니다./bin/sh
따라서 현재 실행 중인 스크립트 및 기타 셸은 이름을 바꿔도 계속 작동하며, 이름을 바꾼 후에는 대시 대신 bash를 호출합니다.
그러나 시스템이 스크립트 편집을 허용하는 방식으로 실행된다면 스크립트를 편집하는 편이 낫습니다.
/bin/sh
링크를 로 대체한 경우 bash
작업이 완료되면 다시 /bin/sh
링크가 되도록 수정하는 것을 잊지 마세요.dash
문제의 스크립트가 바이너리 패키지의 일부인 경우 문제 업스트림에 대한 버그 보고서를 제출하는 것을 잊지 마세요.