Ist es möglich, eine einzelne Skriptdatei zu schreiben, die sowohl unter Windows (als .bat behandelt) als auch unter Linux (über Bash) ausgeführt wird?
Ich kenne die grundlegende Syntax von beiden, habe es aber nicht herausgefunden. Es könnte wahrscheinlich die obskure Syntax von Bash oder einen Fehler im Windows-Batch-Prozessor ausnutzen.
Der auszuführende Befehl kann nur eine einzelne Zeile zum Ausführen eines anderen Skripts sein.
Die Motivation besteht darin, nur einen einzigen Anwendungsstartbefehl für Windows und Linux zu haben.
Update: Das "native" Shell-Skript des Systems muss die richtige Interpreter-Version auswählen, bestimmten bekannten Umgebungsvariablen entsprechen usw. Die Installation zusätzlicher Umgebungen wie CygWin ist nicht vorzuziehen - ich möchte das Konzept beibehalten. " herunterladen & ausführen ".
Die einzige andere Sprache, die für Windows in Betracht gezogen werden muss, ist Windows Scripting Host - WSH, das seit 98 standardmäßig voreingestellt ist.
quelle
cp
eingebaute oder umgekehrt, sodass das Schreiben von zwei separaten Skripten möglicherweise pädagogisch besser ist als die hier gezeigten fortgeschrittenen Techniken.Antworten:
Ich habe die Beschriftungssyntax von cmd als Kommentarmarker verwendet . Das Beschriftungszeichen, ein Doppelpunkt (
:
), entspricht dentrue
meisten POSIXish-Shells. Wenn Sie dem Beschriftungszeichen sofort ein anderes Zeichen folgen, das in a nicht verwendet werden kann, sollte dasGOTO
Kommentieren Ihrescmd
Skripts keinen Einfluss auf Ihrencmd
Code haben.Der Hack besteht darin, Codezeilen nach der Zeichenfolge "
:;
" zu setzen. Wenn Sie hauptsächlich einzeilige Skripte schreiben oder, wie es der Fall sein kann, eine Zeilesh
für viele Zeilen von schreiben können, istcmd
Folgendes möglicherweise in Ordnung. Vergessen Sie nicht , dass die Verwendung von$?
vor dem nächsten Doppelpunkt sein muss ,:
weil:
Resets$?
auf 0.Ein sehr ausgeklügeltes Beispiel für Bewachung
$?
:Eine andere Idee zum Überspringen von
cmd
Code ist die Verwendung von Heredocs, sodasssh
dercmd
Code als nicht verwendete Zeichenfolge behandelt undcmd
interpretiert wird. In diesem Fall stellen wir sicher, dass das Trennzeichen unseres Heredocs in Anführungszeichen steht (um zu verhindernsh
, dass der Inhalt beim Ausführen interpretiert wirdsh
) und mit beginnt,:
sodasscmd
es wie jede andere Zeile, die mit beginnt , überspringt:
.Abhängig von Ihren Anforderungen oder Ihrem Codierungsstil können Interlacing
cmd
undsh
Code sinnvoll sein oder auch nicht. Die Verwendung von Heredocs ist eine Methode, um ein solches Interlacing durchzuführen. Dies könnte jedoch mit derGOTO
Technik erweitert werden :Universelle Kommentare können natürlich mit der Zeichenfolge
: #
oder erfolgen:;#
. Das Leerzeichen oder Semikolon ist erforderlich, da essh
als#
Teil eines Befehlsnamens betrachtet wird, wenn es nicht das erste Zeichen eines Bezeichners ist. Beispielsweise möchten Sie möglicherweise universelle Kommentare in die ersten Zeilen Ihrer Datei schreiben, bevor Sie dieGOTO
Methode zum Teilen Ihres Codes verwenden. Dann können Sie Ihren Leser darüber informieren, warum Ihr Skript so seltsam geschrieben ist:Daher einige Ideen und Möglichkeiten, um Skripte ohne schwerwiegende Nebenwirkungen zu erstellen
sh
und zucmd
kompatibel zu machen, soweit ich weiß (und ohnecmd
Ausgabe'#' is not recognized as an internal or external command, operable program or batch file.
).quelle
.cmd
Erweiterung haben muss, da es sonst nicht unter Windows ausgeführt wird. Gibt es eine Problemumgehung?.cmd
und als ausführbar zu markieren. Auf diese Weise funktioniert die Ausführung des Skripts über die Standard-Shell unter Windows oder Unix (nur mit Bash getestet). Da ich mir keine Möglichkeit vorstellen kann, einen Shebang einzuschließen, ohne dass sich cmd laut beschwert, müssen Sie das Skript immer über eine Shell aufrufen. Das heißt, stellen Sie sicher, dass Sieexeclp()
oderexecvp()
(ich denkesystem()
, dies ist der „richtige“ Weg für Sie) anstelle vonexecl()
oder verwendenexecv()
(diese letzteren Funktionen funktionieren nur bei Skripten mit Shebangs, da sie direkter zum Betriebssystem gehen).<Exec/>
MSBuild Task ) und nicht als unabhängige Batchdateien geschrieben habe. Vielleicht, wenn ich etwas Zeit in der Zukunft habe, werde ich die Antwort mit den Informationen in diesen Kommentaren aktualisieren ...Sie können dies versuchen:
Wahrscheinlich müssen Sie
/r/n
eine neue Zeile anstelle eines Unix-Stils verwenden. Wenn ich mich recht erinnere, wird die neue Unix-Zeile von.bat
Skripten nicht als neue Zeile interpretiert. Eine andere Möglichkeit besteht darin, eine#.exe
Datei im Pfad zu erstellen , die nichts bewirkt Ähnlich wie meine Antwort hier: Ist es möglich, VBScript in eine Batch-Datei einzubetten und auszuführen, ohne eine temporäre Datei zu verwenden?BEARBEITEN
Die Antwort des Binki ist fast perfekt, kann aber noch verbessert werden:
Es verwendet wieder den
:
Trick und den mehrzeiligen Kommentar. Looks wie cmd.exe (zumindest unter Windows 10) funktionieren problemlos mit den EOLs im Unix-Stil. Stellen Sie daher sicher, dass Ihr Skript in das Linux-Format konvertiert ist. (Der gleiche Ansatz wurde bereits hier und hier verwendet ). Obwohl die Verwendung von shebang immer noch eine redundante Ausgabe erzeugt ...quelle
/r/n
am Ende von Zeilen verursacht viele Kopfschmerzen im Bash-Skript, es sei denn, Sie beenden jede Zeile mit einem#
(dh#/r/n
) - auf diese Weise\r
wird das als Teil des Kommentars behandelt und ignoriert.# 2>NUL & ECHO Welcome to %COMSPEC%.
gelingt, den Fehler zu verbergen , dass der#
Befehl von nicht gefunden wirdcmd
. Diese Technik ist nützlich, wenn Sie eine eigenständige Zeile schreiben müssen, die nur voncmd
(z. B. in aMakefile
) ausgeführt wird.Ich wollte einen Kommentar abgeben, kann aber momentan nur eine Antwort hinzufügen.
Die Techniken sind ausgezeichnet und ich benutze sie auch.
Es ist schwierig, eine Datei beizubehalten, in der zwei Arten von Zeilenumbrüchen enthalten sind, nämlich
/n
für den Bash-Teil und/r/n
für den Windows-Teil. Die meisten Editoren versuchen, ein allgemeines Zeilenumbruchschema durchzusetzen, indem sie erraten, welche Art von Datei Sie bearbeiten. Die meisten Methoden zum Übertragen der Datei über das Internet (insbesondere als Text- oder Skriptdatei) waschen die Zeilenumbrüche, sodass Sie mit einer Art von Zeilenumbruch beginnen und mit der anderen enden können. Wenn Sie Annahmen über Zeilenumbrüche gemacht und Ihr Skript dann einer anderen Person zur Verwendung gegeben haben, stellt diese möglicherweise fest, dass es für sie nicht funktioniert.Das andere Problem sind netzwerkmontierte Dateisysteme (oder CDs), die von verschiedenen Systemtypen gemeinsam genutzt werden (insbesondere, wenn Sie die dem Benutzer zur Verfügung stehende Software nicht steuern können).
Man sollte daher den DOS-Zeilenumbruch von verwenden
/r/n
und auch das Bash-Skript vor dem DOS schützen,/r
indem man am Ende jeder Zeile einen Kommentar einfügt (#
). Sie können in bash auch keine Zeilenfortsetzungen verwenden, da/r
diese dadurch unterbrochen werden.Auf diese Weise funktioniert es, wer auch immer das Skript verwendet und in welcher Umgebung auch immer.
Ich benutze diese Methode in Verbindung mit der Erstellung von tragbaren Makefiles!
quelle
Das Folgende funktioniert bei mir ohne Fehler oder Fehlermeldungen mit Bash 4 und Windows 10, im Gegensatz zu den obigen Antworten. Ich nenne die Datei "Whatever.cmd",
chmod +x
mache sie unter Linux ausführbar und mache sie mit Unix-Zeilenenden (dos2unix
), um Bash ruhig zu halten.quelle
Sie können Variablen gemeinsam nutzen:
quelle
Es gibt verschiedene Möglichkeiten, verschiedene Befehle für
bash
und auszuführencmd
mit demselben Skript .cmd
ignoriert Zeilen, die mit beginnen:;
, wie in anderen Antworten erwähnt. Die nächste Zeile wird ebenfalls ignoriert, wenn die aktuelle Zeile mit dem Befehl endetrem ^
, da das^
Zeichen dem Zeilenumbruch entgeht und die nächste Zeile von als Kommentar behandelt wirdrem
.Es gibt mehrere Möglichkeiten
bash
, diecmd
Zeilen zu ignorieren . Ich habe einige Möglichkeiten aufgezählt, um dies zu tun, ohne das zu brechencmd
Befehle :Nicht existent
#
Befehl (nicht empfohlen)Wenn beim Ausführen des Skripts kein
#
Befehl verfügbarcmd
ist, können wir Folgendes tun:Das
#
Zeichen amcmd
Zeilenanfang machtbash
behandelt diese Zeile als Kommentar.Das
#
Zeichen am Ende derbash
Zeile wird verwendet, um das\r
Zeichen zu kommentieren , wie Brian Tompsett in seiner Antwort hervorhob . Andernfallsbash
wird ein Fehler\r\n
ausgegeben, wenn die Datei Zeilenenden hat, die von erforderlich sindcmd
.Auf diese Weise
# 2>nul
versuchen wircmd
, den Fehler eines nicht vorhandenen#
Befehls zu ignorieren , während der folgende Befehl ausgeführt wird.Verwenden Sie diese Lösung nicht, wenn
#
auf dem Befehl ein Befehl verfügbar istPATH
oder wenn Sie keine Kontrolle über die verfügbaren Befehle habencmd
.Verwenden Sie
echo
, um das#
Zeichen zu ignorierencmd
Wir können
echo
mit seiner umgeleiteten Ausgabecmd
Befehle inbash
den auskommentierten Bereich einfügen :Da das
#
Zeichen keine besondere Bedeutung hatcmd
, wird es als Teil des Textes behandeltecho
. Alles was wir tun mussten, ist die Ausgabe desecho
Befehls umzuleiten und danach andere Befehle einzufügen.Leere
#.bat
DateiDie
echo >/dev/null # 1>nul 2> #.bat
Zeile erstellt im eingeschalteten Zustand eine leere#.bat
Dateicmd
(oder ersetzt vorhandene#.bat
, falls vorhanden) und im eingeschalteten Zustand nichtsbash
.Diese Datei wird von den folgenden
cmd
Zeilen verwendet, auch wenn sich#
auf dem Befehl ein anderer Befehl befindetPATH
.Der
del #.bat
Befehl für dencmd
spezifischen Code löscht die erstellte Datei. Sie müssen dies nur in der letztencmd
Zeile tun .Verwenden Sie diese Lösung nicht, wenn sich eine
#.bat
Datei in Ihrem aktuellen Arbeitsverzeichnis befinden könnte, da diese Datei gelöscht wird.Empfohlen: Verwenden Sie here-document , um
cmd
Befehle zu ignorierenbash
Wenn Sie das
^
Zeichen am Ende dercmd
Zeile platzieren, entgehen wir dem Zeilenumbruch und wenn Sie es:
als Trennzeichen für das Dokument verwenden, hat der Inhalt der Trennzeichenzeile keine Auswirkung aufcmd
. Auf diese Weisecmd
wird die:
Zeile erst ausgeführt, nachdem die Zeile beendet ist, und hat das gleiche Verhalten wiebash
.Wenn Sie mehrere Zeilen auf beiden Plattformen haben und diese nur am Ende des Blocks ausführen möchten, können Sie Folgendes tun:
Solange es keine
cmd
genaue Linie gibthere-document delimiter
, sollte diese Lösung funktionieren. Sie könnenhere-document delimiter
zu jedem anderen Text wechseln .In allen vorgestellten Lösungen werden die Befehle erst nach der letzten Zeile ausgeführt , wodurch ihr Verhalten konsistent wird, wenn sie auf beiden Plattformen dasselbe tun.
Diese Lösungen müssen
\r\n
als Zeilenumbrüche in Dateien gespeichert werden , da sie sonst nicht funktionierencmd
.quelle
Die vorherigen Antworten scheinen so ziemlich alle Optionen abzudecken und haben mir sehr geholfen. Ich füge diese Antwort hier ein, um den Mechanismus zu demonstrieren, mit dem ich sowohl ein Bash-Skript als auch ein Windows-CMD-Skript in dieselbe Datei aufgenommen habe.
LinuxWindowsScript.bat
Zusammenfassung
Unter Linux
Die erste Zeile (
echo >/dev/null # >nul & GOTO WINDOWS & rem ^
) wird ignoriert und das Skript durchläuft jede unmittelbar darauf folgende Zeile, bis derexit 0
Befehl ausgeführt wird. Sobald diesexit 0
erreicht ist, wird die Skriptausführung beendet und die Windows-Befehle darunter ignoriert.In Windows
In der ersten Zeile wird der
GOTO WINDOWS
Befehl ausgeführt, wobei die unmittelbar darauf folgenden Linux-Befehle übersprungen werden und die Ausführung in der:WINDOWS
Zeile fortgesetzt wird.Wagenrücklauf in Windows entfernen
Da ich diese Datei unter Windows bearbeitet habe, musste ich die Zeilenumbrüche (\ r) systematisch aus den Linux-Befehlen entfernen, da sonst beim Ausführen des Bash-Teils ungewöhnliche Ergebnisse erzielt wurden. Zu diesem Zweck habe ich die Datei in Notepad ++ geöffnet und Folgendes ausgeführt:
Schalten Sie die Option zum Anzeigen von Zeilenende - Zeichen (
View
>Show Symbol
>Show End of Line
). Wagenrückläufe werden dann alsCR
Zeichen angezeigt.Führen Sie ein Suchen & Ersetzen (
Search
>Replace...
) durch und aktivieren Sie dieExtended (\n, \r, \t, \0, \x...)
Option.Geben Sie
\r
dasFind what :
Feld ein und löschen Sie dasReplace with :
Feld aus, damit nichts darin ist.Klicken Sie oben in der Datei auf die
Replace
Schaltfläche, bis alle Wagenrücklaufzeichen (CR
) aus dem oberen Linux-Bereich entfernt wurden. Stellen Sie sicher, dass dieCR
Zeichen für Wagenrücklauf ( ) für den Windows-Teil belassen werden.Das Ergebnis sollte sein, dass jeder Linux-Befehl nur in einem Zeilenvorschub endet (
LF
) und jeder Windows-Befehl in einem Wagenrücklauf und einem Zeilenvorschub endet (CR
LF
).quelle
Ich benutze diese Technik, um lauffähige JAR-Dateien zu erstellen. Da die jar / zip-Datei am zip-Header beginnt, kann ich ein universelles Skript einfügen, um diese Datei oben auszuführen:
@
in sh einen Fehler auslöst, an den weitergeleitet wird,/dev/null
und danach ein Kommentar beginnt. Auf cmd/dev/null
schlägt die Pipe fehl, da die Datei unter Windows nicht erkannt wird. Da Windows jedoch keinen#
Kommentar erkennt, wird der Fehler an weitergeleitetnul
. Dann gibt es ein Echo aus. Weil der ganzen Zeile ein vorangestellt ist@
, wird auf cmd kein Ausdruck erstellt.::
, der einen Kommentar in cmd startet, noop in sh. Dies hat den Vorteil , dass::
nicht zurückgesetzt$?
zu0
. Es verwendet die ":;
Trick ist ein Etikett".::
und sie werden in cmd ignoriert:: exit
dem sh endet das Skript und ich kann cmd Befehle schreibencommand not found
. Sie müssen selbst entscheiden, ob Sie es brauchen oder nicht.quelle
Ich brauchte dies für einige meiner Python-Paketinstallationsskripte. Die meisten Dinge zwischen sh und bat-Datei sind gleich, aber nur wenige Dinge wie die Fehlerbehandlung sind unterschiedlich. Eine Möglichkeit, dies zu tun, ist wie folgt:
Dann rufen Sie dies aus dem Bash-Skript auf:
Die Windows-Batchdatei sieht folgendermaßen aus:
quelle
Probieren Sie mein BashWin-Projekt unter https://github.com/skanga/bashwin aus , das BusyBox für die meisten Unix-Befehle verwendet
quelle
Es gibt plattformunabhängige Build-Tools wie Ant oder Maven mit XML-Syntax (basierend auf Java). Sie können also alle Ihre Skripte in Ant oder Maven neu schreiben und sie trotz des OS-Typs ausführen. Oder Sie können einfach ein Ant-Wrapper-Skript erstellen, das den Betriebssystemtyp analysiert und das entsprechende Bat- oder Bash-Skript ausführt.
quelle