สคริปต์เดียวที่จะทำงานทั้งใน Windows batch และ Linux Bash?


98

เป็นไปได้ไหมที่จะเขียนไฟล์สคริปต์เดียวซึ่งดำเนินการทั้งใน Windows (ถือว่าเป็น. bat) และ Linux (ผ่าน Bash)

ฉันรู้ไวยากรณ์พื้นฐานของทั้งสอง แต่ไม่เข้าใจ อาจใช้ประโยชน์จากไวยากรณ์ที่คลุมเครือของ Bash หรือความผิดพลาดของตัวประมวลผลแบตช์ของ Windows

คำสั่งในการดำเนินการอาจเป็นเพียงบรรทัดเดียวเพื่อเรียกใช้สคริปต์อื่น

แรงจูงใจคือการมีคำสั่งบูตแอปพลิเคชันเดียวสำหรับทั้ง Windows และ Linux

อัปเดต:ความต้องการเชลล์สคริปต์ "เนทีฟ" ของระบบคือต้องเลือกเวอร์ชันล่ามที่เหมาะสมสอดคล้องกับตัวแปรสภาพแวดล้อมที่รู้จักกันดีบางอย่างเป็นต้นการติดตั้งสภาพแวดล้อมเพิ่มเติมเช่น CygWin ไม่เป็นที่นิยม - ฉันต้องการคงแนวคิด " ดาวน์โหลดและเรียกใช้ "

ภาษาอื่นที่ควรพิจารณาสำหรับ Windows คือ Windows Scripting Host - WSH ซึ่งตั้งค่าไว้ล่วงหน้าตั้งแต่ปี 98


9
มองเข้าไปใน Perl หรือ Python เป็นภาษาสคริปต์ที่มีอยู่ในทั้งสองแพลตฟอร์ม
a_horse_with_no_name

groovy หลามทับทิมทุกคน? stackoverflow.com/questions/257730/…
Kalpesh Soni

Groovy จะดีมากที่มีในทุกระบบโดยค่าเริ่มต้นฉันจะใช้มันเป็นเชลล์สคริปต์ อาจจะสักวันก็ได้ :)
Ondra Žižka

1
ดูเพิ่มเติมที่: github.com/BYVoid/Batsh
Dave Jarvis

2
กรณีการใช้งานที่น่าสนใจสำหรับสิ่งนี้คือบทช่วยสอน - เพื่อให้สามารถบอกคนอื่น ๆ ว่า "เรียกใช้สคริปต์เล็ก ๆ นี้" โดยไม่ต้องอธิบายว่า "ถ้าคุณใช้ Windows ให้ใช้สคริปต์เล็ก ๆ นี้ แต่ถ้าคุณใช้ Linux หรือ Mac ให้ลองทำเช่นนี้ แทนซึ่งฉันยังไม่ได้ทดสอบจริงๆเพราะฉันใช้ Windows " น่าเสียดายที่ Windows ไม่มีคำสั่งพื้นฐานคล้ายยูนิกซ์เช่นcpในตัวหรือในทางกลับกันดังนั้นการเขียนสคริปต์แยกกันสองสคริปต์อาจจะดีกว่าเทคนิคขั้นสูงที่แสดงไว้ที่นี่
Qwertie

คำตอบ:


92

สิ่งที่ฉันได้ทำคือไวยากรณ์ฉลากใช้ cmd เป็นเครื่องหมายแสดงความคิดเห็น อักขระป้ายกำกับโคลอน ( :) เทียบเท่ากับtrueในเชลล์ POSIXish ส่วนใหญ่ หากคุณติดตามอักขระป้ายกำกับทันทีด้วยอักขระอื่นที่ไม่สามารถใช้ใน a ได้การ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.)


5
โปรดสังเกตว่าสิ่งนี้ต้องการให้สคริปต์มี.cmdส่วนขยายมิฉะนั้นจะไม่ทำงานใน Windows มีวิธีแก้ปัญหาใด ๆ หรือไม่?
jviotti

1
หากคุณกำลังเขียนไฟล์แบตช์ฉันขอแนะนำให้ตั้งชื่อไฟล์เหล่านั้น.cmdและทำเครื่องหมายว่าปฏิบัติการได้ ด้วยวิธีนี้การเรียกใช้สคริปต์จากเชลล์เริ่มต้นบน Windows หรือ unix จะทำงานได้ (ทดสอบด้วย bash เท่านั้น) เนื่องจากฉันไม่สามารถคิดวิธีรวม shebang โดยไม่ทำให้ cmd บ่นเสียงดังคุณต้องเรียกใช้สคริปต์ผ่านเชลล์เสมอ กล่าวคือต้องแน่ใจว่าได้ใช้execlp()หรือexecvp()(ฉันคิดว่าsystem()นี่เป็นวิธีที่“ ถูกต้อง” สำหรับคุณ) มากกว่าexecl()หรือexecv()(ฟังก์ชันหลังเหล่านี้จะใช้ได้เฉพาะกับสคริปต์ที่มี shebangs เท่านั้นเนื่องจากไปที่ระบบปฏิบัติการโดยตรงมากกว่า)
binki

ฉันละเว้นการสนทนาเกี่ยวกับนามสกุลไฟล์เนื่องจากฉันเขียนโค้ดพกพาในเชลล์เอาต์ (เช่น<Exec/>MSBuild Task ) แทนที่จะเป็นไฟล์แบตช์อิสระ บางทีถ้าฉันมีเวลาในอนาคตฉันจะอัปเดตคำตอบพร้อมข้อมูลในความคิดเห็นเหล่านี้ ...
binki

23

คุณสามารถลองสิ่งนี้:

#|| 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 จะยังคงให้ผลลัพธ์ที่ซ้ำซ้อน ...


3
/r/nในตอนท้ายของบรรทัดจะทำให้ปวดหัวมากใน bash script เว้นแต่คุณจะจบแต่ละบรรทัดด้วย#(เช่น#/r/n) - วิธี\rนี้จะถือว่าเป็นส่วนหนึ่งของความคิดเห็นและถูกเพิกเฉย
Gordon Davisson

2
อันที่จริงผมพบว่า# 2>NUL & ECHO Welcome to %COMSPEC%.การบริหารจัดการเพื่อซ่อนข้อผิดพลาดเกี่ยวกับคำสั่งไม่ได้ถูกค้นพบโดย# cmdเทคนิคนี้มีประโยชน์เมื่อคุณต้องเขียนเส้นเดี่ยวที่จะดำเนินการโดยcmd(เช่นใน a Makefile) เท่านั้น
binki

11

ฉันต้องการแสดงความคิดเห็น แต่สามารถเพิ่มคำตอบได้ในขณะนี้

เทคนิคที่ให้มานั้นยอดเยี่ยมมากและฉันก็ใช้มันด้วย

เป็นการยากที่จะเก็บรักษาไฟล์ที่มีตัวแบ่งบรรทัดสองประเภทอยู่ภายในไฟล์นั่นคือ/nสำหรับส่วน bash และ/r/nสำหรับส่วน windows บรรณาธิการส่วนใหญ่พยายามบังคับใช้โครงร่างการแบ่งบรรทัดทั่วไปโดยคาดเดาว่าคุณกำลังแก้ไขไฟล์ประเภทใด นอกจากนี้วิธีการโอนไฟล์ทางอินเทอร์เน็ตส่วนใหญ่ (โดยเฉพาะในรูปแบบไฟล์ข้อความหรือสคริปต์) จะเป็นการล้างการแบ่งบรรทัดดังนั้นคุณสามารถเริ่มต้นด้วยการแบ่งบรรทัดประเภทหนึ่งและลงท้ายด้วยอีกแบบหนึ่ง หากคุณตั้งสมมติฐานเกี่ยวกับการแบ่งบรรทัดแล้วมอบสคริปต์ของคุณให้คนอื่นใช้อาจพบว่าไม่ได้ผลสำหรับพวกเขา

ปัญหาอื่น ๆ คือระบบไฟล์ที่ติดตั้งบนเครือข่าย (หรือซีดี) ที่ใช้ร่วมกันระหว่างประเภทระบบต่างๆ (โดยเฉพาะที่คุณไม่สามารถควบคุมซอฟต์แวร์ที่มีให้สำหรับผู้ใช้)

ดังนั้นจึงควรใช้การแบ่งบรรทัด DOS /r/nและป้องกันสคริปต์ทุบตีจาก DOS /rด้วยการใส่ความคิดเห็นที่ท้ายแต่ละบรรทัด ( #) นอกจากนี้คุณยังไม่สามารถใช้การต่อเนื่องของเส้นในการทุบตีเพราะ/rจะทำให้เส้นแตก

ด้วยวิธีนี้ใครก็ตามที่ใช้สคริปต์และในสภาพแวดล้อมใดก็ตามมันก็จะทำงานได้

ฉันใช้วิธีนี้ร่วมกับการสร้าง Makefiles แบบพกพา!


6

ต่อไปนี้ใช้งานได้สำหรับฉันโดยไม่มีข้อผิดพลาดหรือข้อความแสดงข้อผิดพลาดกับ Bash 4 และ Windows 10 ซึ่งแตกต่างจากคำตอบด้านบน ฉันตั้งชื่อไฟล์ว่า "what.cmd" ทำchmod +xเพื่อให้สามารถเรียกใช้งานได้ใน linux และทำให้มันมีส่วนท้ายบรรทัด unix ( 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

3

มีหลายวิธีในการดำเนินการคำสั่งที่แตกต่างกัน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ให้ละเว้นข้อผิดพลาดของ#คำสั่งที่ไม่มีอยู่จริงในขณะที่ยังคงเรียกใช้คำสั่งที่ตามมา

อย่าใช้วิธีนี้ถ้ามี#คำสั่งที่มีอยู่บนหรือถ้าคุณไม่มีการควบคุมเกินคำสั่งที่สามารถใช้ได้PATHcmd


ใช้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ไฟล์ในขณะที่cmd(หรือแทนที่ที่มีอยู่#.batถ้ามี) bashและไม่ทำอะไรเลยในขณะที่

ไฟล์นี้จะถูกใช้โดยcmdบรรทัดที่ตามหลังแม้ว่าจะมี#คำสั่งอื่นในไฟล์PATH.

del #.batคำสั่งในcmdรหัส -specific ลบไฟล์ที่ถูกสร้างขึ้น คุณต้องทำสิ่งนี้ในcmdบรรทัดสุดท้ายเท่านั้น

อย่าใช้วิธีนี้หาก#.batไฟล์อาจอยู่ในไดเร็กทอรีการทำงานปัจจุบันของคุณเนื่องจากไฟล์นั้นจะถูกลบ


แนะนำ: การใช้เอกสารที่นี่เพื่อละเว้นcmdคำสั่งบนbash

:; echo 'Hello bash!';<<:
echo Hello cmd! & ^
:

โดยการวาง^ตัวละครในตอนท้ายของcmdเส้นที่เรากำลังหลบหนีแบ่งบรรทัดและโดยใช้เป็นตัวคั่นที่นี่เอกสารเนื้อหาเส้นคั่นจะไม่มีผลกระทบต่อ: 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\ncmd


ดีกว่าไม่มาสาย ... สิ่งนี้ช่วยฉันได้มากกว่าคำตอบอื่น ๆ ขอบคุณ !!
A-Diddy


2

คำตอบก่อนหน้านี้ดูเหมือนจะครอบคลุมตัวเลือกทั้งหมดและช่วยฉันได้มาก ฉันรวมคำตอบนี้ไว้ที่นี่เพื่อแสดงให้เห็นถึงกลไกที่ฉันใช้เพื่อรวมทั้งสคริปต์ 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 ที่อยู่ด้านล่าง

ใน Windows

บรรทัดแรกจะดำเนินการGOTO WINDOWSคำสั่งโดยข้ามคำสั่ง Linux ตามไปทันทีและดำเนินการต่อที่:WINDOWSบรรทัด

การลบ Carriage Returns ใน Windows

เนื่องจากฉันกำลังแก้ไขไฟล์นี้ใน Windows ฉันจึงต้องลบการคืนค่าการขนส่ง (\ r) ออกจากคำสั่ง Linux อย่างเป็นระบบมิฉะนั้นฉันได้ผลลัพธ์ที่ผิดปกติเมื่อเรียกใช้ส่วน Bash ในการทำสิ่งนี้ฉันเปิดไฟล์ในNotepad ++และทำสิ่งต่อไปนี้:

  1. เปิดตัวเลือกสำหรับการดูส่วนท้ายของตัวละครสาย ( View> Show Symbol> Show End of Line) จากนั้นการคืนค่าขนส่งจะแสดงเป็นCRอักขระ

  2. ทำการค้นหาและแทนที่ ( Search> Replace...) และExtended (\n, \r, \t, \0, \x...)เลือกตัวเลือก

  3. ประเภท\rในFind what :ภาคสนามและว่างเปล่าออกReplace with :ภาคสนามเพื่อให้มีอะไรอยู่ในนั้น

  4. เริ่มต้นที่ด้านบนสุดของไฟล์คลิกReplaceปุ่มจนกระทั่งCRอักขระreturn ( ) ทั้งหมดถูกลบออกจากส่วนบนของ Linux อย่าลืมทิ้งCRอักขระreturn ( ) ของแคร่ตลับหมึกไว้สำหรับส่วน Windows

ผลลัพธ์ควรจะเป็นที่คำสั่ง Linux แต่ละคำสั่งสิ้นสุดในบรรทัด feed ( LF) และคำสั่ง Windows แต่ละคำสั่งจะสิ้นสุดใน carriage return และ line feed ( CR LF)


ใน Notepad ++ เพียงเลือกแก้ไข> การแปลง EOL> LFไม่จำเป็นต้องทำการแทนที่ดังกล่าว และไม่จำเป็นต้องทำทุกครั้งเพียงตั้งค่า LF เป็นค่าเริ่มต้นหากจำเป็นในการตั้งค่า> การตั้งค่า มิฉะนั้นจะมีหลายวิธีในการแปลง CRLF บน Windows
phuclv

2

ฉันใช้เทคนิคนี้เพื่อสร้างไฟล์ jar ที่รันได้ เนื่องจากไฟล์ jar / zip เริ่มต้นที่ส่วนหัว zip ฉันสามารถใส่สคริปต์สากลเพื่อเรียกใช้ไฟล์นี้ที่ด้านบน:

#!/usr/bin/env sh\n
@ 2>/dev/null # 2>nul & echo off & goto BOF\r\n
:\n
<shell commands go here with \n line endings>
exit\n
\r\n
:BOF\r\n
<cmd commands go here with \r\n line endings>\r\n
exit /B %errorlevel%\r\n
}

การตั้งค่าส่วนท้ายบรรทัดตามที่ระบุไว้ข้างต้นเป็นสิ่งสำคัญเนื่องจากอาจทำให้เกิดปัญหาในแพลตฟอร์มต่างๆ นอกจากนี้คำสั่ง goto จะทำงานไม่ถูกต้องในบางกรณีหากไม่มีการสิ้นสุดบรรทัดที่เหมาะสมรอบ ๆ ป้ายกระโดด

เทคนิคข้างต้นคือสิ่งที่ฉันใช้ในปัจจุบัน ด้านล่างนี้เป็นเวอร์ชันที่ล้าสมัยพร้อมคำอธิบายเชิงลึก:

#!/usr/bin/env sh
@ 2>/dev/null # 2>nul & echo off
:; alias ::=''
:: exec java -jar $JAVA_OPTS "$0" "$@"
:: exit
java -jar %JAVA_OPTS% "%~dpnx0" %*
exit /B
  • บรรทัดแรกสะท้อนออกใน cmd และไม่พิมพ์อะไรบน sh เนื่องจาก@ใน sh ส่งข้อผิดพลาดที่ถูกส่งไปยัง/dev/nullและหลังจากนั้นความคิดเห็นจะเริ่มขึ้น เมื่อวันที่ cmd ท่อเพื่อ/dev/nullล้มเหลวเนื่องจากไฟล์ไม่ได้รับการยอมรับใน Windows แต่เนื่องจากหน้าต่างไม่ได้ตรวจสอบว่าเป็นความคิดเห็นข้อผิดพลาดประปาไป# nulจากนั้นจะปิดเสียงสะท้อน เนื่องจากบรรทัดทั้งหมดนำหน้าด้วย@จึงไม่ได้รับ printet บน cmd
  • อันที่สองกำหนด::ซึ่งเริ่มต้นความคิดเห็นใน cmd ถึง noop ใน sh นี้มีผลประโยชน์ที่::ไม่ได้ตั้งค่าการ$? 0ใช้:;เคล็ดลับ "เป็นป้ายกำกับ"
  • ตอนนี้ฉันสามารถนำหน้าคำสั่ง sh ได้และคำสั่ง::เหล่านี้จะถูกละเว้นใน cmd
  • ใน:: exitสคริปต์ sh สิ้นสุดลงและฉันสามารถเขียนคำสั่ง cmd ได้
  • เพียงบรรทัดแรก (shebang) เป็นปัญหาใน cmd command not foundเพราะมันจะพิมพ์ คุณต้องตัดสินใจเองว่าคุณต้องการหรือไม่

0

ฉันต้องการสิ่งนี้สำหรับสคริปต์การติดตั้งแพ็คเกจ Python ของฉัน สิ่งต่างๆระหว่างไฟล์ sh และ bat จะเหมือนกัน แต่มีบางอย่างเช่นการจัดการข้อผิดพลาดที่แตกต่างกัน วิธีหนึ่งในการดำเนินการดังต่อไปนี้:

common.inc
----------
common statement1
common statement2

จากนั้นคุณเรียกสิ่งนี้จากสคริปต์ทุบตี:

linux.sh
--------
# do linux specific stuff
...
# call common code
source common.inc

ไฟล์แบตช์ของ Windows มีลักษณะดังนี้:

windows.bat
-----------
REM do windows specific things
...
# call common code
call common.inc


-6

มีเครื่องมือสร้างแพลตฟอร์มที่เป็นอิสระเช่น Ant หรือ Maven พร้อมไวยากรณ์ xml (อิงตาม Java) ดังนั้นคุณสามารถเขียนสคริปต์ทั้งหมดของคุณใหม่ใน Ant หรือ Maven และรันได้แม้จะมีประเภท OS ก็ตาม หรือคุณสามารถสร้างสคริปต์ Ant wrapper ซึ่งจะวิเคราะห์ประเภทของระบบปฏิบัติการและเรียกใช้ bat หรือ bash script ที่เหมาะสม


5
ดูเหมือนว่าจะเป็นการใช้เครื่องมือเหล่านั้นในทางที่ผิดอย่างร้ายแรง หากคุณต้องการหลีกเลี่ยงคำถามจริง (ทำงานในเนทีฟเชลล์) คุณควรแนะนำภาษาสคริปต์สากลเช่น python ไม่ใช่เครื่องมือสร้างที่สามารถใช้ในทางที่ผิดแทนภาษาสคริปต์ที่เหมาะสมได้
ArtOfWarfare
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.