쉘 스크립트는 인코딩 및 줄 끝에 민감합니까?

bash shell sh


Mac에서 NW.js 앱을 만들고 있는데 아이콘을 두 번 클릭하여 개발 모드에서 앱을 실행하고 싶습니다. 첫 번째 단계로 쉘 스크립트를 작동 시키려고합니다.

Windows에서 VSCode를 사용하여 (시간을 얻고 싶었습니다) 프로젝트의 루트에 다음을 포함 하는 run-nw 파일을 만들었습니다 .

#!/bin/bash

cd "src"
npm install

cd ..
./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &

그러나 나는이 출력을 얻는다 :

$ sh ./run-nw

: command not found  
: No such file or directory  
: command not found  
: No such file or directory  

Usage: npm <command>

where <command> is one of:  (snip commands list)

(snip npm help)

npm@3.10.3 /usr/local/lib/node_modules/npm  
: command not found  
: No such file or directory  
: command not found

나는 정말로 이해하지 못한다 :

  • 명령으로 빈 줄이 필요한 것 같습니다. 내 편집기 (VSCode)에서 \r\n\n 으로 바꾸려고했지만 ( \r 문제가 발생하는 경우) 아무것도 변경되지 않습니다.
  • dirname 명령 이 있거나없는 폴더를 찾지 못 하거나 cd 명령 에 대해 모르는 것 같습니다 .
  • npminstall 인수를 이해하지 못하는 것 같습니다.
  • 정말 이상하게 여기는 부분은 여전히 ​​앱을 실행한다는 것입니다 (Npm을 수동으로 npm install 한 경우 ) ...

파일이 제대로 작동하지 않고 파일 자체에 이상한 점이 의심되면 vim을 사용하여 Mac에서 직접 새로운 파일을 만들었습니다. 나는 똑같은 지침을 입력했으며 이제는 아무런 문제없이 작동합니다.
두 파일의 차이는 정확히 0의 차이를 나타냅니다.

차이점은 무엇입니까? 첫 번째 스크립트가 작동하지 않게 할 수있는 것은 무엇입니까? 어떻게 알 수 있습니까?

Update

수락 된 답변의 명령에 따라 잘못된 줄 끝이 다시 나타난 후에 여러 가지를 확인했습니다. Windows 컴퓨터에서 ~/.gitconfig 를 복사 autocrlf=true 가 있었 으므로 Windows에서 bash 파일을 수정할 때마다 줄 끝을 \r\n 다시 설정합니다 .
따라서 dos2unix (mac에서 Homebrew를 사용하여 설치해야 함)를 실행하는 것 외에도 Git을 사용하는 경우 구성을 확인하십시오.




Answer 1 Anthony Geoghegan


예. Bash 스크립트 스크립트 자체와 처리하는 데이터 모두에서 줄 끝에 민감합니다. 유닉스 스타일의 줄 끝을 가져야합니다. 즉, 각 줄은 줄 바꿈 문자 (10 진수, 16 진수 0A ASCII)로 끝납니다.

스크립트의 DOS / Windows 줄 끝

Windows 또는 DOS 스타일 줄 끝으로 각 줄은 캐리지 리턴으로 끝나고 줄 바꿈 문자가 뒤에옵니다. 스크립트 파일이 Windows 줄 끝으로 저장된 경우 Bash는 파일을

#!/bin/bash^M
^M
cd "src"^M
npm install^M
^M
cd ..^M
./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &^M

참고 : 캐럿 표기법을 사용하여 인쇄하지 않는 문자를 나타 냈습니다. 즉 ^M 은 캐리지 리턴 문자를 나타내는 데 사용됩니다 ( 다른 컨텍스트 에서는 \r 로 표시됨). 이것은 cat -v 및 Vim에서 사용하는 것과 동일한 기술 입니다.

이 경우 캐리지 리턴 ( ^M 또는 \r )은 공백으로 처리되지 않습니다. Bash는 shebang 뒤의 첫 번째 행 (단일 캐리지 리턴 문자로 구성됨)을 실행할 명령 / 프로그램의 이름으로 해석합니다.

  • ^M 이라는 명령이 없으므로 : command not found 인쇄합니다 . command not found
  • "src"^M (또는 src^M ) 이라는 디렉토리가 없으므로 : No such file or directory 인쇄됩니다 .
  • 그것은 전달 install^M 대신 install 인수로 npm 발생 npm 불평.

입력 데이터의 DOS / Windows 줄 끝

위와 같이 캐리지 리턴이있는 입력 파일이있는 경우 :

hello^M
world^M

편집기에서는 화면에 쓸 때 완전히 정상적으로 보이지만 도구는 이상한 결과를 낳을 수 있습니다. 예를 들어, grep 은 분명히 다음 줄을 찾지 못합니다.

$ grep 'hello$' file.txt || grep -x "hello" file.txt
(no match because the line actually ends in ^M)

캐리지 리턴이 커서를 줄의 시작 부분으로 이동하기 때문에 추가 된 텍스트가 대신 줄을 덮어 씁니다.

$ sed -e 's/$/!/' file.txt
!ello
!orld

화면에 쓸 때 문자열이 동일 해 보이지만 문자열 비교는 실패한 것 같습니다.

$ a="hello"; read b < file.txt
$ if [[ "$a" = "$b" ]]
  then echo "Variables are equal."
  else echo "Sorry, $a is not equal to $b"
  fi

Sorry, hello is not equal to hello

Solutions

해결책은 파일을 Unix 스타일 줄 끝을 사용하도록 변환하는 것입니다. 이를 수행 할 수있는 여러 가지 방법이 있습니다.

  1. dos2unix 프로그램을 사용하여 수행 할 수 있습니다 .

    dos2unix filename
  2. 유능한 텍스트 편집기 (Sublime, Notepad ++, 메모장이 아님) 에서 파일을 열고 Unix 줄 끝으로 파일을 저장하도록 구성하십시오 (예 : Vim 등).

    :set fileformat=unix
  3. -i 또는 --in-place 옵션 (예 : GNU sed ) 을 지원 하는 sed 유틸리티 버전이있는 경우 다음 명령을 실행하여 후행 캐리지 리턴을 제거 할 수 있습니다.

    sed -i 's/\r$//' filename

    sed 의 다른 버전 에서는 출력 리디렉션을 사용하여 새 파일에 쓸 수 있습니다. 리디렉션 대상에 다른 파일 이름을 사용해야합니다 (나중에 이름을 바꿀 수 있음).

    sed 's/\r$//' filename > filename.unix
  4. 마찬가지로 tr 변환 필터를 사용하여 입력에서 원하지 않는 문자를 삭제할 수 있습니다.

    tr -d '\r' <filename >filename.unix

시그윈 배쉬

Cygwin 용 Bash 포트에는 줄 바꿈으로 캐리지 리턴을 무시하도록 설정할 수 있는 사용자 정의 igncr 옵션이 있습니다 (아마도 많은 사용자가 기본 Windows 프로그램을 사용하여 텍스트 파일을 편집하기 때문에). set -o igncr 을 실행 하여 현재 쉘에 사용할 수 있습니다 .

이 옵션을 설정하면 현재 쉘 프로세스 에만 적용 되므로 캐리지 리턴이 불필요한 파일을 소싱 할 때 유용 합니다. DOS 줄 끝으로 쉘 스크립트를 정기적으로 발견하고이 옵션을 영구적으로 설정하려면 SHELLOPTS (모든 대문자) 라는 환경 변수 를 igncr 을 포함하도록 설정할 수 있습니다. 이 환경 변수는 Bash에서 시작시 (시작 파일을 읽기 전에) 쉘 옵션을 설정하는 데 사용됩니다.

유용한 유틸리티

file 유틸리티 라인 엔딩 텍스트 파일에 사용되는 신속하게 보는 데 유용합니다. 다음은 각 파일 형식에 대해 인쇄되는 내용입니다.

  • 유닉스 줄 끝 : Bourne-Again shell script, ASCII text executable
  • Mac 줄 끝 : Bourne-Again shell script, ASCII text executable, with CR line terminators
  • DOS 줄 끝 : Bourne-Again shell script, ASCII text executable, with CRLF line terminators

cat 유틸리티 의 GNU 버전 에는 비 인쇄 문자를 표시 하는 -v, --show-nonprinting 옵션이 있습니다.

dos2unix 유틸리티는 특히 유닉스, Mac 및 DOS 라인 엔딩 사이에 텍스트 파일을 변환하기 위해 작성되었습니다.

유용한 링크

Wikipedia에는 텍스트 줄의 끝을 표시하는 여러 가지 방법, 그러한 인코딩의 역사 및 다른 운영 체제, 프로그래밍 언어 및 인터넷 프로토콜 (예 : FTP)에서 줄 바꿈이 처리되는 방법을 다루는 훌륭한 기사 가 있습니다.

클래식 Mac OS 줄 끝이있는 파일

함께 클래식 맥 OS (사전 OS X), 각 행은 캐리지 리턴 (십진수 13 ASCII의 진수 0D)와 함께 종료되었습니다. 스크립트 파일이 줄 끝으로 저장된 경우 Bash는 다음과 같이 하나의 긴 줄만 표시합니다.

#!/bin/bash^M^Mcd "src"^Mnpm install^M^Mcd ..^M./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &^M

이 단일 긴 행은 옥토 프 ( # )로 시작하므로 Bash는 행 (및 전체 파일)을 단일 주석으로 취급합니다.

참고 : 2001 년 Apple은 BSD 파생 NeXTSTEP 운영 체제를 기반으로하는 Mac OS X을 출시했습니다 . 결과적으로 OS X는 Unix 스타일의 LF 전용 줄 끝을 사용하기 때문에 CR로 끝나는 텍스트 파일은 매우 드물게되었습니다. 그럼에도 불구하고 Bash가 이러한 파일을 해석하려고 시도하는 방법을 보여줄 가치가 있다고 생각합니다.




Answer 2 CONvid19


JetBrains의 제품 (PyCharm, PHPStorm, IDEA 등)에, 당신은해야합니다 clickCRLF / LF 하는 전환 라인 분리의 두 가지 유형 (사이 \r\n\n ).

enter image description here enter image description here




Answer 3 Igor Soudakevitch


원하지 않는 CR ( '\ r') 문자를 제거하는 또 다른 방법은 tr 명령 을 실행하는 것 입니다. 예를 들면 다음과 같습니다.

$ tr -d '\r' < dosScript.py > nixScript.py



Answer 4 tripleee


복제본에서 나온 파일 이름에 ^M 포함 된 파일이 있으면 문제의 이름 을 바꿀 수 있습니다.

for f in *$'\r'; do
    mv "$f" "${f%$'\r'}"
done

이 파일들이 처음에 이름이 깨진 원인을 수정하고 싶을 것입니다 (아마도 dos2unix 을 만든 스크립트는 dos2unix ed 다음 다시 실행해야합니까?). 그러나 때로는 이것이 가능하지 않습니다.

$'\r' 구문은 Bash 전용입니다; 다른 쉘을 사용하는 경우 다른 표기법을 사용해야 할 수도 있습니다. 아마도 sh와 bash의 차이점을 참조하십시오.




Answer 5 danR


MAC / Linux에서 가장 간단한 방법- 'touch'명령을 사용하여 파일을 생성하고 VI 또는 VIM 편집기로이 파일을 연 다음 코드를 붙여넣고 저장하십시오. 윈도우 문자가 자동으로 제거됩니다.