Ich bin sehr, sehr neu in der UNIX-Programmierung (lauffähig auf MacOSX Mountain Lion via Terminal). Ich habe die Grundlagen aus einem Kurs für Bioinformatik und molekulare Methoden (wir hatten zwei Klassen) gelernt, in dem wir Perl und Python für die Datenverwaltung verwenden werden. Wie auch immer, wir wurden mit dem Schreiben eines Shell-Skripts beauftragt, um Daten aus einer Gruppe von Dateien in eine neue Datei in einem Format zu schreiben, das von einem bestimmten Programm (Migrate-N) gelesen werden kann.
Ich habe eine Reihe von Funktionen bekommen, um genau das zu tun, was ich unabhängig brauche, wenn ich sie in die Befehlszeile eingebe. Wenn ich sie jedoch alle in einem Skript zusammenstelle und versuche, es auszuführen, erhalte ich eine Fehlermeldung. Hier sind die Details (ich entschuldige mich für die Länge):
#! /bin/bash
grep -f Samples.NFCup.txt locus1.fasta > locus1.NFCup.txt
grep -f Samples.NFCup.txt locus2.fasta > locus2.NFCup.txt
grep -f Samples.NFCup.txt locus3.fasta > locus3.NFCup.txt
grep -f Samples.NFCup.txt locus4.fasta > locus4.NFCup.txt
grep -f Samples.NFCup.txt locus5.fasta > locus5.NFCup.txt
grep -f Samples.Salmon.txt locus1.fasta > locus1.Salmon.txt
grep -f Samples.Salmon.txt locus2.fasta > locus2.Salmon.txt
grep -f Samples.Salmon.txt locus3.fasta > locus3.Salmon.txt
grep -f Samples.Salmon.txt locus4.fasta > locus4.Salmon.txt
grep -f Samples.Salmon.txt locus5.fasta > locus5.Salmon.txt
grep -f Samples.Cascades.txt locus1.fasta > locus1.Cascades.txt
grep -f Samples.Cascades.txt locus2.fasta > locus2.Cascades.txt
grep -f Samples.Cascades.txt locus3.fasta > locus3.Cascades.txt
grep -f Samples.Cascades.txt locus4.fasta > locus4.Cascades.txt
grep -f Samples.Cascades.txt locus5.fasta > locus5.Cascades.txt
echo 3 5 Salex_melanopsis > Smelanopsis.mig
echo 656 708 847 1159 779 >> Smelanopsis.mig
echo 154 124 120 74 126 NFCup >> Smelanopsis.mig
cat locus1.NFCup.txt locus2.NFCup.txt locus3.NFCup.txt locus4.NFCup.txt locus5.NFCup.txt >> Smelanopsis.mig
echo 32 30 30 18 38 Salmon River >> Smelanopsis.mig
cat locus1.Salmon.txt locus2.Salmon.txt locus3.Salmon.txt locus4.Salmon.txt locus5.Salmon.txt >> Smelanopsis.mig
echo 56 52 24 29 48 Cascades >> Smelanopsis.mig
cat locus1.Cascades.txt locus2.Cascades.txt locus3.Cascades.txt locus4.Cascades.txt locus5.Cascades.txt >> Smelanopsis.mig
Die Greps-Serie zieht nur DNA-Sequenzdaten für jeden Standort für jeden Ort in neue Textdateien. Die Samples ...-TXT-Dateien enthalten die Sample-ID-Nummern für eine Site. Die .fasta-Dateien enthalten die Sequenzinformationen nach Sample-ID. Das Grepping funktioniert gut in der Befehlszeile, wenn ich es einzeln starte.
Die zweite Gruppe von Code erstellt die eigentliche neue Datei, die am Ende benötigt wird. Sie endet in .mig. Die Echolinien sind Daten zu Zählungen (Basenpaare pro Locus, Populationen in der Analyse, Proben pro Standort usw.), zu denen das Programm Informationen benötigt. Die Katzenzeilen mischen den Ort nach Standortdaten, die von allen Begrüßungen unterhalb der standortspezifischen Informationen erstellt werden, die in der Echozeile vorgegeben sind. Sie erhalten zweifellos das Bild.
Zum Erstellen des Shell-Skripts habe ich in Excel angefangen, so dass ich die Zellen leicht kopieren und einfügen/automatisch ausfüllen kann. Als Text mit Tabulatortrennzeichen speichern und dann die Textdatei in TextWrangler öffnen, um die Tabulatoren zu entfernen, bevor sie als .sh-Datei (Zeile bricht: Unix (LF) und Encoding: Unicode (UTF-8)) im selben Verzeichnis wie alle im Skript verwendeten Dateien. Ich habe versucht, mit chmod +x FILENAME.sh
und chmod u+x FILENAME.sh
zu versuchen, sicherzustellen, dass es ausführbar ist, jedoch ohne Erfolg. Selbst wenn ich das Skript auf eine einzige grep-Zeile (mit der ersten Zeile #!/Bin/bash) reduziere, kann ich es nicht schaffen. Der Vorgang dauert nur einen Moment, wenn ich ihn direkt in die Befehlszeile eingebe, da keine dieser Dateien größer als 160 KB ist und einige erheblich kleiner sind. Dies ist, was ich eingebe und wenn ich versuche, die Datei auszuführen (HW ist das richtige Verzeichnis)
localhost:HW Mirel$ MigrateNshell.sh
-bash: MigrateNshell.sh: command not found
Ich bin jetzt seit zwei Tagen bei diesem Unpass dabei, daher wäre jede Eingabe sehr dankbar! Vielen Dank!!
Aus Sicherheitsgründen durchsucht die Shell das aktuelle Verzeichnis (standardmäßig) nicht nach einer ausführbaren Datei. Sie müssen genau sein und bash
mitteilen, dass sich Ihr Skript im aktuellen Verzeichnis (.
) befindet:
$ ./MigrateNshell.sh
Ändern Sie die erste Zeile wie folgt von Marc B
#!/bin/bash
Markieren Sie dann das Skript als ausführbar und führen Sie es über die Befehlszeile aus
chmod +x MigrateNshell.sh
./MigrateNshell.sh
oder führen Sie einfach bash von der Kommandozeile aus und übergeben Sie Ihr Skript als Parameter
/bin/bash MigrateNshell.sh
Stellen Sie sicher, dass Sie "PATH" nicht als Variable verwenden. Dadurch wird der vorhandene PATH für Umgebungsvariablen überschrieben.
Versuchen Sie auch, das Shell-Skript zu dos2unix
zu benennen, da es manchmal Windows-Zeilenenden hat und die Shell es nicht erkennt.
$ dos2unix MigrateNshell.sh
Das hilft manchmal.
Es gab einige gute Kommentare zum Hinzufügen der Shebang-Zeile am Anfang des Skripts. Ich möchte eine Empfehlung hinzufügen, um den env-Befehl zu verwenden, um die Portabilität zu erhöhen.
Während #!/bin/bash
möglicherweise der richtige Ort auf Ihrem System ist, ist dies nicht universell. Darüber hinaus ist dies möglicherweise nicht die bevorzugt bash des Benutzers. #!/usr/bin/env bash
wählt die erste im Pfad gefundene Bash aus.
chmod u+x MigrateNshell.sh
ausprobieren
#! /bin/bash
^---
entfernen Sie den angegebenen Platz. Der Shebang sollte sein
#!/bin/bash
Unix hat eine Variable namens PATH
, die eine Liste von Verzeichnissen ist, in denen Befehle gesucht werden.
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Users/david/bin
Wenn ich in der Befehlszeile einen Befehl foo
eingebe, wird meine Shell zuerst sehen, ob es einen ausführbaren Befehl /usr/local/bin/foo
gibt. Wenn ja, wird /usr/local/bin/foo
ausgeführt. Wenn nicht, wird festgestellt, ob es einen ausführbaren Befehl /usr/bin/foo
gibt, und wenn nicht, prüft es, ob /bin/foo
vorhanden ist usw., bis es zu /Users/david/bin/foo
gelangt.
Wenn es in keinem dieser Verzeichnisse einen Befehl foo
findet, sagen Sie mir Befehl nicht gefunden .
Es gibt mehrere Möglichkeiten, wie ich mit diesem Problem umgehen kann:
bash foo
, da foo
ein Shell-Skript ist./Users/david/foo
oder $PWD/foo
oder einfach nur ./foo
.$PATH
-Variable, um das Verzeichnis, das Ihre Befehle enthält, zum PATH hinzuzufügen.Sie können $HOME/.bash_profile
oder $HOME/.profile
ändern, wenn .bash_profile
nicht vorhanden ist. Ich habe das getan, um /usr/local/bin
hinzuzufügen, den ich zuerst in meinen Pfad eingefügt habe. Auf diese Weise kann ich die Standardbefehle im Betriebssystem überschreiben. Ich habe zum Beispiel Ant 1.9.1, aber der Mac kam mit Ant 1.8.4. Ich habe meinen ant
-Befehl in /usr/local/bin
gestellt, so dass meine Version von ant
zuerst ausgeführt wird. Ich habe auch $HOME/bin
am Ende des PATH für meine eigenen Befehle hinzugefügt. Wenn ich eine Datei wie die, die Sie ausführen möchten, hatte, platziere ich sie in $ HOME/bin, um sie auszuführen.
Stellen Sie außerdem sicher, dass/bin/bash der richtige Ort für bash ist. Wenn Sie diese Zeile aus einem Beispiel entnommen haben, stimmt sie möglicherweise nicht mit Ihrem Server überein. Wenn Sie einen ungültigen Speicherort für Bash angeben, wird ein Problem auftreten.
Fügen Sie unten in Ihrem .profile-Pfad Zeilen hinzu
PATH=$PATH:$HOME/bin:$Dir_where_script_exists
export PATH
Jetzt sollte Ihr Skript ohne ./
funktionieren.
Raj Dagla
Ich bin auch neu im Shell-Scripting, aber ich hatte das gleiche Problem. Stellen Sie sicher, dass Sie am Ende Ihres Skripts eine Leerzeile haben. Sonst funktioniert es nicht.