bash 자주 발생 하 는 오류

1. for i in `ls *.mp3`
일반적인 오류 쓰기:
for i in `ls *.mp3`; do     # Wrong!

왜 틀 렸 을까요?for... in 문 구 는 공백 에 따라 단 어 를 나 누 기 때문에 빈 칸 을 포함 하 는 파일 이름 은 여러 단어 로 분 리 됩 니 다.01 - Don 't Eat the Yellow Snow. mp3 를 만나면 i 의 값 은 순서대로 01, -, Don' t, 등등 을 취한 다.
작은 따옴표 로 도 안 됩 니 다. ls * mp3 의 모든 결 과 를 하나의 단어 로 처리 합 니 다.
for i in "`ls *.mp3`"; do   # Wrong!

정확 한 표기 법 은?
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 ]    # 正确

아니면 아예 변 수 를 오른쪽 에 두 세 요. [명령 의 등호 오른쪽 은 공백 이나 횡선 으로 시작 하 더 라 도 정상적으로 작 동 할 수 있 기 때 문 입 니 다. (자바 프로 그래 밍 스타일 에 도 비슷 한 방법 이 있 습 니 다. 목적 은 다 르 지만.)
[ 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 my file]초보 자 들 이 자주 저 지 르 는 실 수 는 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 언어 가 아 닙 니 다.그러나 here document 출력 시 echo 대신 cat 를 사용 해 야 합 니 다.
# This is wrong:
echo <<EOF
Hello world
EOF
 
# This is right:
cat <<EOF
Hello world
EOF

16. su - c 'some command' 원문 은 기본적으로 정확 하지만 사용자 의 목적 은 - c 'some command' 를 셸 에 전달 하 는 것 입 니 다. 마침 su 는 - c 인자 가 있 기 때문에 su 는 'some 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;
bar
baz

디 렉 터 리 에 관 한 한 문제 외 에 셸 프로그램 에서 작업 디 렉 터 리 를 자주 바 꾸 려 고 한다 고 가정 합 니 다. 예 를 들 어 아래 코드 와 같 습 니 다.
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 등의 명령 을 유연 하 게 사용 하여 작업 디 렉 터 리 를 제어 할 수 있 습 니 다.
[ 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. cmd 1 & & cmd 2 | | cmd 3 는 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 +H
echo "Hello, world!"

23. for arg in $* $* 는 모든 명령 행 인 자 를 표시 하기 때문에 매개 변 수 를 하나씩 처리 하려 고 할 수도 있 지만 매개 변수 에 빈 칸 이 포함 되 어 있 을 때 실패 합 니 다. 예 를 들 어:
#!/bin/bash
# Incorrect version
for x in $*; do
  echo "parameter: '$x'"
done
 
$ ./myscript 'arg 1' arg2 arg3
parameter: 'arg'
parameter: '1'
parameter: 'arg2'
parameter: 'arg3'

올 바른 방법 은 '$@' 을 사용 하 는 것 입 니 다.
#!/bin/bash
# Correct version
for x in "$@"; do
  echo "parameter: '$x'"
done
 
$ ./myscript 'arg 1' arg2 arg3
parameter: '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() {
  ...
}

 

좋은 웹페이지 즐겨찾기