Windows (.bat로 처리)와 Linux (Bash를 통해) 모두에서 실행되는 단일 스크립트 파일을 작성할 수 있습니까?
나는 둘 다의 기본 구문을 알고 있지만 이해하지 못했습니다. Bash의 모호한 구문이나 Windows 배치 프로세서 결함을 악용 할 수 있습니다.
실행할 명령은 다른 스크립트를 실행하는 한 줄일 수 있습니다.
동기 부여는 Windows와 Linux 모두에 대해 단일 응용 프로그램 부팅 명령을 갖는 것입니다.
업데이트 : 시스템의 “네이티브”쉘 스크립트에 대한 필요성은 올바른 인터프리터 버전을 선택하고 특정 잘 알려진 환경 변수를 준수해야한다는 것입니다. CygWin과 같은 추가 환경을 설치하는 것은 바람직하지 않습니다. 개념을 유지하고 싶습니다. ” 다운로드 및 실행 “.
Windows에서 고려해야 할 유일한 다른 언어는 Windows Scripting Host-WSH이며, 이는 98 이후 기본적으로 사전 설정되어 있습니다.
답변
내가 한 일은 cmd의 레이블 구문을 주석 마커로 사용하는 것 입니다. 레이블 문자 인 콜론 ( :
) true
은 대부분의 POSIX 쉘에서 와 동일합니다 . 에서 사용할 수없는 다른 문자가 레이블 문자 바로 뒤에 오는 경우 스크립트에 GOTO
주석을 달아도 코드에 cmd
영향을주지 않습니다 cmd
.
해킹은 문자 시퀀스 ” :;
” 뒤에 코드 줄을 넣는 것 입니다. 대부분 한 줄짜리 스크립트를 작성하거나 경우 sh
에 따라 여러 줄에 대해 한 줄을 작성할 cmd
수 있다면 다음과 같이해도 좋습니다. 의 모든 사용은 0으로 재설정 되므로 $?
다음 콜론 앞에 있어야합니다 .:
:
$?
:; echo "Hi, I’m ${SHELL}."; exit $?
@ECHO OFF
ECHO I'm %COMSPEC%
가드의 매우 인위적인 예 $?
:
:; false; ret=$?
:; [ ${ret} = 0 ] || { echo "Program failed with code ${ret}." >&2; exit 1; }
:; exit
ECHO CMD code.
스킵에 대한 또 다른 생각이 cmd
코드를 사용하는 것입니다 heredocs을 수 있도록 sh
를 대우 cmd
하지 않는 문자열과 같은 코드를 cmd
해석 그것. 이 경우 heredoc의 구분 기호가 모두 따옴표로 묶여 있고 (로 sh
실행할 때 내용에 대한 모든 종류의 해석 을 중지하기 위해 sh
)로 시작하여로 시작 하는 다른 줄처럼 건너 뛰 :
도록합니다 .cmd
:
:; echo "I am ${SHELL}"
:<<"::CMDLITERAL"
ECHO I am %COMSPEC%
::CMDLITERAL
:; echo "And ${SHELL} is back!"
:; exit
ECHO And back to %COMSPEC%
필요 나 코딩 스타일에 따라 인터레이스 cmd
와 sh
코드가 의미가있을 수도 있고 그렇지 않을 수도 있습니다. heredocs를 사용하는 것은 이러한 인터레이스를 수행하는 한 가지 방법입니다. 그러나 이것은 GOTO
기술 로 확장 할 수 있습니다 .
:<<"::CMDLITERAL"
@ECHO OFF
GOTO :CMDSCRIPT
::CMDLITERAL
echo "I can write free-form ${SHELL} now!"
if :; then
echo "This makes conditional constructs so much easier because"
echo "they can now span multiple lines."
fi
exit $?
:CMDSCRIPT
ECHO Welcome to %COMSPEC%
물론 범용 주석은 문자 시퀀스 : #
또는 :;#
. 공백 또는 세미콜론은 식별자의 첫 문자가 아닌 경우 명령 이름의 일부로 sh
간주 되기 때문에 필요 #
합니다. 예를 들어 GOTO
메서드를 사용 하여 코드를 분할 하기 전에 파일의 첫 번째 줄에 범용 주석을 작성할 수 있습니다. 그런 다음 독자에게 스크립트가 이상하게 작성된 이유를 알릴 수 있습니다.
: # This is a special script which intermixes both sh
: # and cmd code. It is written this way because it is
: # used in system() shell-outs directly in otherwise
: # portable code. See /programming/17510688
: # for details.
:; echo "This is ${SHELL}"; exit
@ECHO OFF
ECHO This is %COMSPEC%
따라서 내가 아는 한 심각한 부작용없이 (그리고 출력 없이 ) 스크립트 를 완성 sh
하고 cmd
호환 되는 몇 가지 아이디어와 방법 .cmd
'#' is not recognized as an internal or external command, operable program or batch file.
답변
당신은 이것을 시도 할 수 있습니다 :
#|| goto :batch_part
echo $PATH
#exiting the bash part
exit
:batch_part
echo %PATH%
아마도 /r/n
유닉스 스타일 대신 새 줄로 사용해야 할 것 입니다. 정확한 것을 기억한다면 유닉스 줄 바꿈은 스크립트에 의해 새 줄로 해석되지 않습니다 .bat
. 또 다른 방법은 #.exe
경로에 아무것도하지 않는 파일 을 만드는 것입니다. 내 대답과 비슷한 방식으로 임시 파일을 사용하지 않고 배치 파일 내에 VBScript를 포함하고 실행할 수 있습니까?
편집하다
binki의 대답은 거의 완벽하지만 여전히 개선 될 수있다 :
:<<BATCH
@echo off
echo %PATH%
exit /b
BATCH
echo $PATH
그것은 다시 :
트릭과 여러 줄 주석을 사용합니다. cmd.exe (적어도 windows10에서는)가 유닉스 스타일 EOL에 문제없이 작동하므로 스크립트가 Linux 형식으로 변환되는지 확인하십시오. (이전에 여기 와 여기에 동일한 접근 방식이 사용되었습니다 ). shebang을 사용하면 여전히 중복 출력이 생성되지만 …
답변
댓글을 달고 싶었지만 지금은 답변 만 추가 할 수 있습니다.
주어진 기술은 훌륭하고 나도 사용합니다.
/n
bash 부분과 /r/n
창 부분에 대한 두 가지 종류의 줄 바꿈이 포함 된 파일을 유지하는 것은 어렵습니다 . 대부분의 편집자는 편집중인 파일의 종류를 추측하여 일반적인 줄 바꿈 체계를 적용하려고합니다. 또한 인터넷을 통해 파일을 전송하는 대부분의 방법 (특히 텍스트 또는 스크립트 파일)은 줄 바꿈을 세탁하므로 한 종류의 줄 바꿈으로 시작하여 다른 종류로 끝낼 수 있습니다. 줄 바꿈에 대한 가정을 한 다음 다른 사람에게 스크립트를 제공하면 해당 스크립트가 작동하지 않을 수 있습니다.
다른 문제는 서로 다른 시스템 유형 (특히 사용자가 사용할 수있는 소프트웨어를 제어 할 수없는 경우)간에 공유되는 네트워크 마운트 파일 시스템 (또는 CD)입니다.
따라서 DOS 줄 바꿈을 사용해야하며 각 줄 끝에 주석을 추가하여 /r/n
DOS에서 bash 스크립트를 보호해야합니다 /r
( #
). 또한 bash에서 줄 연속을 사용할 수 없습니다 /r
.
이런 식으로 스크립트를 사용하는 사람과 어떤 환경에서든 작동합니다.
이 방법은 휴대용 Makefile을 만드는 것과 함께 사용합니다!
답변
다음은 위의 답변과 달리 Bash 4 및 Windows 10에서 오류 또는 오류 메시지없이 저에게 효과적입니다. 파일 이름을 “whatever.cmd”로 지정하고 chmod +x
Linux에서 실행 가능하게 만들고 dos2unix
bash를 조용하게 유지하기 위해 유닉스 줄 끝 ( )을 사용하도록합니다.
:; if [ -z 0 ]; then
@echo off
goto :WINDOWS
fi
if [ -z "$2" ]; then
echo "usage: $0 <firstArg> <secondArg>"
exit 1
fi
# bash stuff
exit
:WINDOWS
if [%2]==[] (
SETLOCAL enabledelayedexpansion
set usage="usage: %0 <firstArg> <secondArg>"
@echo !usage:"=!
exit /b 1
)
:: windows stuff
답변
변수를 공유 할 수 있습니다.
:;SET() { eval $1; }
SET var=value
:;echo $var
:;exit
ECHO %var%
답변
에 다른 명령을 실행하는 방법은 여러 가지가 있습니다 bash
와 cmd
같은 스크립트는.
cmd
:;
다른 답변에서 언급했듯이으로 시작하는 줄을 무시 합니다. 또한 현재 줄이 명령으로 끝나면 다음 줄을 무시합니다 rem ^
. ^
문자는 줄 바꿈을 이스케이프하고 다음 줄은 주석으로 처리됩니다 rem
.
선 을 bash
무시하는 cmd
방법에는 여러 가지가 있습니다. cmd
명령 을 중단하지 않고이를 수행하는 몇 가지 방법을 열거했습니다 .
존재하지 않는 #
명령 (권장되지 않음)
스크립트가 실행될 때 #
사용할 수있는 명령 이없는 경우 다음 cmd
을 수행 할 수 있습니다.
# 2>nul & echo Hello cmd! & rem ^
echo 'Hello bash!' #
#
의 시작 부분에 캐릭터 cmd
라인 차종은 bash
주석으로 그 라인을 취급합니다.
#
의 끝에 문자 bash
라인은 주석하는 데 사용됩니다 \r
브라이언 Tompsett는 지적으로, 문자를 그의 대답 . 이것이 없으면 bash
파일에 \r\n
에서 요구하는 줄 끝 이 있으면 오류가 발생합니다 cmd
.
를 수행함으로써 # 2>nul
우리는 cmd
존재하지 않는 일부 #
명령 의 오류를 무시하는 동시에 다음 명령을 계속 실행합니다.
에서 #
사용할 수 있는 명령이 PATH
있거나에서 사용할 수 있는 명령을 제어 할 수없는 경우이 솔루션을 사용하지 마십시오 cmd
.
문자 echo
무시에 사용#
cmd
의 주석 처리 된 영역 에 명령 echo
을 삽입하기 위해 리디렉션 된 출력과 함께 사용할 수 있습니다 .cmd
bash
echo >/dev/null # >nul & echo Hello cmd! & rem ^
echo 'Hello bash!' #
이후 #
문자가 의미하는 특별한이 없습니다 cmd
, 그것은에있는 텍스트의 한 부분으로 처리됩니다 echo
. 우리가해야 할 일은 echo
명령 의 출력을 리디렉션하고 그 뒤에 다른 명령을 삽입하는 것뿐입니다.
빈 #.bat
파일
echo >/dev/null # 1>nul 2> #.bat
# & echo Hello cmd! & del #.bat & rem ^
echo 'Hello bash!' #
이 echo >/dev/null # 1>nul 2> #.bat
줄은 #.bat
on 동안 빈 파일을 만들고 cmd
(또는 기존 #.bat
,있는 경우 대체 ) on 동안 아무 작업도 수행하지 않습니다 bash
.
이 파일은에 cmd
다른 #
명령 이 있더라도 다음 행에서 사용됩니다 PATH
.
특정 코드 의 del #.bat
명령 cmd
은 생성 된 파일을 삭제합니다. 마지막 cmd
줄 에서만이 작업을 수행하면됩니다 .
#.bat
파일이 현재 작업 디렉토리에있을 수있는 경우이 솔루션을 사용하지 마십시오 . 해당 파일이 지워집니다.
권장 : here-document 를 사용하여 cmd
명령 무시bash
:; echo 'Hello bash!';<<:
echo Hello cmd! & ^
:
줄 ^
끝에 문자 를 배치하면 cmd
줄 바꿈을 이스케이프 :
하고 here-document 구분 기호로 사용하면 구분 기호 줄 내용이에 영향을 미치지 않습니다 cmd
. 그렇게하면, cmd
애프터에만 광고를 실행 :
선이 끝난 동일한 동작을 갖는 bash
.
두 플랫폼 모두에 여러 줄을 사용하고 블록 끝에서만 실행하려면 다음을 수행하십시오.
:;( #
:; echo 'Hello' #
:; echo 'bash!' #
:; );<<'here-document delimiter'
(
echo Hello
echo cmd!
) & rem ^
here-document delimiter
cmd
정확히 가있는 줄 이없는 here-document delimiter
한이 솔루션이 작동합니다. here-document delimiter
다른 텍스트로 변경할 수 있습니다 .
제시된 모든 솔루션 에서 명령은 마지막 줄 이후에만 실행 되므로 두 플랫폼에서 동일한 작업을 수행하면 동작이 일관되게됩니다.
이러한 솔루션은 \r\n
줄 바꿈 으로 파일에 저장해야합니다 . 그렇지 않으면에서 작동하지 않습니다 cmd
.
답변
이전 답변은 거의 모든 옵션을 다루고 많은 도움이되었습니다. 이 답변은 동일한 파일에 Bash 스크립트와 Windows CMD 스크립트를 모두 포함하는 데 사용한 메커니즘을 보여주기 위해 여기에 포함되었습니다.
LinuxWindowsScript.bat
echo >/dev/null # >nul & GOTO WINDOWS & rem ^
echo 'Processing for Linux'
# ***********************************************************
# * NOTE: If you modify this content, be sure to remove carriage returns (\r)
# * from the Linux part and leave them in together with the line feeds
# * (\n) for the Windows part. In summary:
# * New lines in Linux: \n
# * New lines in Windows: \r\n
# ***********************************************************
# Do Linux Bash commands here... for example:
StartDir="$(pwd)"
# Then, when all Linux commands are complete, end the script with 'exit'...
exit 0
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
:WINDOWS
echo "Processing for Windows"
REM Do Windows CMD commands here... for example:
SET StartDir=%cd%
REM Then, when all Windows commands are complete... the script is done.
요약
Linux에서
첫 번째 줄 ( echo >/dev/null # >nul & GOTO WINDOWS & rem ^
)은 무시되고 스크립트는 exit 0
명령이 실행될 때까지 바로 다음 줄을 따라 흐릅니다 . 일단 exit 0
도달, 스크립트 실행은 아래의 윈도우 명령을 무시하고 종료됩니다.
Windows에서
첫 번째 줄은 GOTO WINDOWS
명령 을 실행하고 바로 뒤 따르는 Linux 명령을 건너 뛰고 해당 :WINDOWS
줄 에서 계속 실행 합니다.
Windows에서 캐리지 리턴 제거
Windows에서이 파일을 편집하고 있었기 때문에 Linux 명령에서 캐리지 리턴 (\ r)을 체계적으로 제거해야했습니다. 그렇지 않으면 Bash 부분을 실행할 때 비정상적인 결과를 얻었습니다. 이를 위해 메모장 ++ 에서 파일을 열고 다음을 수행했습니다.
-
라인 문자의 끝을보기위한 옵션을 설정 (
View
>Show Symbol
>Show End of Line
). 그러면 캐리지 리턴이CR
문자 로 표시됩니다 . -
찾기 및 바꾸기 (
Search
>Replace...
)를 수행하고Extended (\n, \r, \t, \0, \x...)
옵션을 확인합니다 . -
필드를 입력
\r
하고Find what :
필드에Replace with :
아무것도 없도록 비워 둡니다 . -
파일의 맨 위에서 시작 하여 맨 위 Linux 부분에서
Replace
모든 캐리지 리턴 (CR
) 문자가 제거 될 때까지 단추를 클릭하십시오 .CR
Windows 부분 에는 캐리지 리턴 ( ) 문자 를 그대로 두십시오 .
그 결과 각 Linux 명령은 줄 바꿈 ( LF
)으로 끝나고 각 Windows 명령은 캐리지 리턴과 줄 바꿈 ( CR
LF
)으로 끝납니다 .
