BASH 프로 그래 밍 에서 만 날 수 있 는 24 개의 함정
10690 단어 shell
일반적인 오류 쓰기:
for i in `ls *.mp3`; do # 错误!
왜 틀 렸 을까요?for... in 문 구 는 공백 에 따라 단 어 를 나 누 기 때문에 빈 칸 을 포함 하 는 파일 이름 은 여러 단어 로 분 리 됩 니 다.
만나다 "01 - Don 't Eat the Yellow Snow. mp3"시 i 의 값 은 순서대로 01, - "Don' t, 등등 을 취한 다.
작은 따옴표 로 도 안 됩 니 다. ls * mp3 의 모든 결 과 를 하나의 단어 로 처리 합 니 다.
for i in "`ls *.mp3`"; do # 错误!
정확 한 표기 법 은?
for i in *.mp3; do # 正确
2. cp $file $target
이 말 은 기본적으로 정확 하지만, 마찬가지 로 빈 칸 분사 의 문제 가 있다.그래서 따옴표 로 해 야 합 니 다.
cp "$file" "$target"
그러나 공교롭게도 파일 이름 이 '-' 로 시작 하면 이 파일 이름 은 cp 에서 명령 행 옵션 으로 처리 되 어 여전히 골 치 아프다.
아래 이 걸 로 해 보 세 요.
cp -- "$file" "$target"
운 이 나 빠 서 지원 되 지 않 는 시스템 을 만 났 습 니 다. 다음 방법 만 사용 할 수 있 습 니 다. 모든 변 수 를 디 렉 터 리 로 시작 합 니 다.
for i in ./*.mp3; do cp "$i" /target ...
3. [ $foo = "bar"]
$foo 가 비어 있 을 때 위의 명령 이 변 합 니 다.
[ = "bar" ]
유사 하 게 $foo 에 빈 칸 이 포함 되 어 있 을 때:
[ multiple words here = "bar" ]
둘 다 틀 릴 거 야.따라서 두 따옴표 로 변 수 를 묶 어야 합 니 다.
[ "$foo" = bar ] # 几乎完美了。
그러나 $foo 가 "-"로 시작 할 때 도 문제 가 있 습 니 다.새로운 bash 에서 당신 은 아래 의 방법 으로 대체 할 수 있 습 니 다. [키 워드 는 공백, 빈 칸, 가로 선 등 문 제 를 정확하게 처리 할 수 있 습 니 다.
[[ $foo = bar ]] # 正确
이전 버 전 bash 에서 이 기술 을 사용 할 수 있 습 니 다 (이해 하기 어렵 지만):
[ x"$foo" = xbar ] # 正确,x可以用abc等替换。
아니면 아예 변 수 를 오른쪽 에 두 세 요. [명령 의 등호 오른쪽 은 공백 이나 횡선 으로 시작 하 더 라 도 정상적으로 작 동 할 수 있 기 때 문 입 니 다. (자바 프로 그래 밍 스타일 에 도 비슷 한 방법 이 있 습 니 다. 목적 은 다 르 지만.)
[ bar = "$foo" ] # 正确
4. cd `dirname "$f"`
빈 칸 문제 도 있 습 니 다. 그럼 따옴표 를 붙 여 주세요.
cd "`dirname "$f"`"
문제 가 생 겼 습 니 다. 잘못 썼 습 니까? 작은 따옴표 가 끼 워 져 있 기 때문에 'dirname 은 첫 번 째 문자열 입 니 다.' 두 번 째 문자열 입 니 다. 틀 렸 습 니 다. 그것 은 C 언어 입 니 다. bash 에서 작은 따옴표 (') 의 내용 을 바 꾸 라 는 명령 을 내 렸 습 니 다. 그 안에 있 는 작은 따옴표 가 정확하게 일치 할 것 입 니 다. 특별히 의 미 를 바 꿀 필요 가 없습니다.
$() 문법 도 같 습 니 다. 아래 의 문법 이 정확 합 니 다.
cd "$(dirname "$f")"
5. [ "$foo"= bar && "$bar"= foo ]
[에 서 는 & & 기 호 를 사용 할 수 없습니다! [실질 적 으로 test 명령 입 니 다. & & 이 줄 을 두 개의 명령 으로 나 눌 것 입 니 다. 다음 과 같은 표기 법 을 사용 해 야 합 니 다.
[ bar = "$foo" -a foo = "$bar" ] # Right!
[ bar = "$foo" ] && [ foo = "$bar" ] # Also right!
[[ $foo = bar && $bar = foo ]] # Also right!
6. [[ $foo > 7 ]]
안 타 깝 게 도 [문자열 에 만 적 용 됩 니 다. 숫자 비 교 는 이렇게 써 야 합 니 다.
(( $foo > 7 ))
또는 고전적 인 서법 으로:
[ $foo -gt 7 ]
그러나 위 에서 사용 한 - lt 의 쓰기 에 문제 가 있 습 니 다. $foo 가 숫자 가 아 닐 때 오류 가 발생 합 니 다. 유형 검 사 를 잘 해 야 합 니 다.
이렇게 써 도 돼.
[[ $foo -gt 7 ]]
7. grep foo bar | while read line; do ((count++) ); done
형식 문제 로 제목 에 빈 칸 을 하나 더 넣 었 습 니 다. 실제 코드 는 다음 과 같 습 니 다.
grep foo bar | while read line; do ((count++)); done # 错误!
이 줄 코드 는 bar 파일 에 foo 를 포함 하 는 줄 수 를 세 어 줍 니 다. 번 거 롭 지만 (grep - c foo bar 나 grep foo bar | wc - l 과 같 습 니 다. 언뜻 보기 에는 문제 가 없 지만 실행 후 count 변 수 는 값 이 없습니다. 파이프 의 모든 명령 을 새 하위 셸 에 넣 고 실행 하기 때문에 하위 셸 에서 정의 하 는 count 변 수 는 전달 할 수 없습니다.
8. if [grep foo myfile]
초보 자 들 이 자주 저 지 르 는 실 수 는 if 구문 뒤의 [if 문법 의 일부분 으로 생각 합 니 다. 실제로 이것 은 if 문법 이 아 닌 test 명령 에 해당 하 는 명령 입 니 다. 이 점 은 C 프로그래머 들 이 특히 주의해 야 합 니 다.
if 는 if 에서 then 사이 의 모든 명령 의 반환 값 을 판단 조건 으로 합 니 다. 따라서 위의 문 구 는 써 야 합 니 다.
if grep foo myfile > /dev/null; then
9. if [bar="$foo"]
마찬가지 로 [명령 입 니 다. if 문장의 일부분 이 아니 므 로 빈 칸 에 주의해 야 합 니 다.
if [ bar = "$foo" ]
10. if [ [ a = b ] && [ c = d ] ]
같은 문제 입 니 다. [if 문장의 일부분 이 아 닙 니 다. 물론 논리 적 판단 을 바 꾸 는 괄호 도 아 닙 니 다. 명령 입 니 다. C 프로그래머 가 쉽게 실 수 를 할 수 있 습 니까?
if [ a = b ] && [ c = d ] # 正确
11. cat file | sed s/foo/bar/> file
같은 파이프 작업 에서 파일 을 동시에 읽 고 쓸 수 없습니다. 파이프 의 구현 방식 에 따라 file 은 0 바이트 로 절단 되 거나 하 드 디스크 전 체 를 채 울 때 까지 무한 증가 합 니 다. 원본 파일 의 내용 을 바 꾸 려 면 임시 파일 에 출력 을 기록 한 다음 뮤 직 비디오 명령 을 사용 해 야 합 니 다.
sed 's/foo/bar/g' file > tmpfile && mv tmpfile file
12. echo $foo
이 말 에 또 무슨 오류 가 있 습 니까? 일반적으로 정확 하지만 아래 의 예 에 문제 가 있 습 니 다.
MSG="Please enter a file name of the form *.zip"echo $MSG # 错误!
마침 현재 디 렉 터 리 에 zip 파일 이 있 으 면
Please enter a file name of the form freenfss.zip lw35nfss.zip
그 러 니까 echo 라 도 변수 에 따 옴 표를 붙 이 는 것 을 잊 지 마 세 요.
13. $foo=bar
변 수 를 할당 할 때 $기 호 를 추가 할 필요 가 없습니다. 이것 은 Perl 이나 PHP 가 아 닙 니 다.
14. foo = bar
변수 할당 시 등호 양쪽 에 빈 칸 을 추가 할 수 없습니다. 이것 은 C 언어 가 아 닙 니 다.
15. echo <
# This is wrong:echo <<EOFHello worldEOF# This is right:cat <<EOFHello worldEOF
16. su -c 'some command'
원문 은 기본적으로 정확 하지만 사용자 의 목적 은 - c 'some command' 를 셸 에 전달 하 는 것 입 니 다. 마침 su 는 - c 인자 가 있 기 때문에 su 는 'ome command' 를 셸 에 게 만 전달 합 니 다. 따라서 이렇게 써 야 합 니 다.
su root -c 'some command'
그러나 내 플랫폼 에서 man su 의 결과 에서 - c 에 대한 해석 은
-c, --commmand=COMMAND pass a single COMMAND to the shell with -c
즉, - c 'some command' 역시 - c 'some command' 라 는 문자열 을 셸 에 전달 하 는데 이것 과 맞지 않 습 니 다. 어쨌든 이 문자열 을 여기에 쓰 세 요.
17. cd/foo; bar
cd 가 잘못 되 었 을 수도 있 습 니 다. 오류 가 발생 하면 bar 명령 은 예상 치 못 한 디 렉 터 리 에서 실 행 됩 니 다. 따라서 cd 의 반환 값 을 판단 하 는 것 을 기억 하 십시오.
cd /foo && bar
cd 의 반환 값 에 따라 여러 명령 을 수행 하려 면 | | 을 사용 할 수 있 습 니 다.
cd /foo || exit 1;barbaz
디 렉 터 리 에 관 한 한 문제 외 에 셸 프로그램 에서 작업 디 렉 터 리 를 자주 바 꾸 려 고 한다 고 가정 합 니 다. 예 를 들 어 아래 코드 와 같 습 니 다.
find ... -type d | while read subdir; do cd "$subdir" && whatever && ... && cd -done
이렇게 쓰 는 것 이 낫다.
find ... -type d | while read subdir; do (cd "$subdir" && whatever && ...)done
괄호 는 하위 셸 을 강제로 시작 합 니 다. 이 하위 셸 에서 작업 디 렉 터 리 를 바 꾸 면 부모 셸 (이 스 크 립 트 를 실행 하 는 셸) 에 영향 을 주지 않 고 cd - 번 거 로 움 을 줄 일 수 있 습 니 다.
pushd, popd, dirs 등 명령 을 활용 하여 작업 디 렉 터 리 를 제어 할 수 있 습 니 다.
18. [ bar == "$foo"]
[명령 에 서 는 사용 할 수 없습니다 = =
[ bar = "$foo" ] && echo yes[[ bar == $foo ]] && echo yes
19. for i in {1..10}; do ./something &; done
& 뒤에 더 이상 놓 지 말 아야 합 니 다. 왜냐하면 & 는 이미 구문 구분자 의 역할 을 했 기 때문에 더 이상 사용 할 필요 가 없습니다.
for i in {1..10}; do ./something & done
20. cmd1 && cmd2 || cmd3
if... then... else 구 조 를 대체 하 는 것 을 좋아 하 는 사람 이 있 습 니 다. 하지만 완전히 같 지 는 않 습 니 다. cmd 2 가 비 진 값 으로 돌아 가면 cmd 3 는 실 행 됩 니 다. 그 러 니 if cmd 1, then cmd 2, else cmd 3 를 성실 하 게 사용 하 는 것 이 좋 습 니 다.
21. UTF - 8 의 BOM (Byte - Order Marks) 문제
UTF - 8 인 코딩 은 파일 의 시작 부분 에 인 코딩 된 바이트 순 서 를 몇 개의 바이트 로 표시 할 수 있 습 니 다. 이 바이트 들 을 BOM 이 라 고 부 릅 니 다. 그러나 유 닉 스 형식의 UTF - 8 인 코딩 은 BOM 이 필요 하지 않 습 니 다. 불필요 한 BOM 은 셸 해석 에 영향 을 줄 수 있 습 니 다. 특히 시작 하 는\#!/bin/sh 와 같은 명령 은 인식 할 수 없습니다.
MS - DOS 형식의 줄 바 꿈 문자 (CRLF) 도 같은 문제 가 있 습 니 다. 셸 프로그램 을 DOS 형식 으로 저장 하면 스 크 립 트 를 실행 할 수 없습니다.
$ ./dos-bash: ./dos: /bin/sh^M: bad interpreter: No such file or directory
22. echo "Hello World!"
이 명령 을 대화 식 으로 실행 하면 다음 과 같은 오류 가 발생 합 니 다.
-bash: !": event not found
왜냐하면! "명령 행 의 과거 기록 을 바 꾸 는 기호 로 처 리 됩 니 다. 그러나 셸 스 크 립 트 에 서 는 이러한 문제 가 없습니다.
불 행 히 도, 당신 은 전의 부 를 사용 하여 의 미 를 바 꿀 수 없습니다!:
$ echo "hi\!"hi\!
솔 루 션 중 하나, 작은 따옴표 사용, 즉
$ echo 'Hello, world!'
따옴표 를 사용 해 야 한다 면 set + H 를 통 해 명령 행 의 과거 기록 교 체 를 취소 해 보 세 요.
set +Hecho "Hello, world!"
23. for arg in $*
$* 모든 명령 행 인 자 를 표시 하기 때문에 매개 변 수 를 하나씩 처리 하려 고 할 수도 있 지만 매개 변수 에 빈 칸 이 포함 되 어 있 을 때 실패 합 니 다. 예 를 들 어:
#!/bin/bash# Incorrect versionfor x in $*; do echo "parameter: '$x'"done$ ./myscript 'arg 1' arg2 arg3parameter: 'arg'parameter: '1'parameter: 'arg2'parameter: 'arg3'
올 바른 방법 은 '$@' 을 사용 하 는 것 입 니 다.
#!/bin/bash# Correct versionfor x in "$@"; do echo "parameter: '$x'"done$ ./myscript 'arg 1' arg2 arg3parameter: 'arg 1'parameter: 'arg2'parameter: 'arg3'
bash 매 뉴 얼 에서 $* 와 $@ 에 대한 설명 은 다음 과 같 습 니 다.
* Expands to the positional parameters, starting from one.
When the expansion occurs within double quotes, it expands to a single word with the value of each parameter separated by the first character of the IFS special variable.
That is, "$*" is equivalent to "$1c$2c...", @Expands to the positional parameters, starting from one.
When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$@" is equivalent to "$1" "$2" ...
이 를 통 해 알 수 있 듯 이 따옴표 가 붙 지 않 을 때 $* 와 $@ 은 같 지만 '$*' 는 문자열 로 확장 되 고 '$@' 은 매개 변수 로 확 장 됩 니 다.
24. function foo()
bash 에 서 는 문제 가 없 지만 다른 셸 에 서 는 오류 가 발생 할 수 있 습 니 다. function 과 괄호 를 함께 사용 하지 마 세 요. 가장 안전 한 방법 은 괄호 를 사용 하 는 것 입 니 다. 즉,
foo() { ...}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
ZSH에서 물고기까지ZSH는 수년 동안 내 기본 셸이었습니다. 이제 몇 달 동안 사용하면서 ZSH 구성에 대해 몇 가지 사항을 발견했습니다. 우리는 을 제공하는 시스템과 더 빨리 상호 작용하는 경향이 있습니다. 내.zshrc 구성에는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.