Ich habe den folgenden Fehler erhalten:
./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution und dies ist das Skript:
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"} echo $no done Kommentare
- Was versuchst du mit den Zahnspangen zu erreichen? Zitieren Sie auch Ihre Variablen.
- Siehe Warum wird die Ausgabe von ' als schlechte Vorgehensweise wiederholt? A. >
Antwort
 ${ ... } (geschweifte Klammern) markiert mehrere Arten von  Parametererweiterung , von denen die einfachste nur das Erweitern des Werts einer Variablen ist. Das Material in geschweiften Klammern in Ihrem Code ist kein „gültiger Parametername oder eine andere Erweiterung, daher beschwert sich die Shell. 
Sie scheinen stattdessen eine Befehlsersetzung zu wollen, dafür lautet die Syntax (reguläre Klammer).
 Auch die ls in ls $filename | sed... scheint etwas zu sein Unnötig, die Variable wird zu Ihrem Dateinamen erweitert und ls leitet sie einfach weiter. Sie können stattdessen auch echo "$filename" | sed ... verwenden. 
Sie können diese Änderungen jedoch direkt in der Shell vornehmen:
no="${filename/assemblyDB.}" # remove first match no="${no/.las}" oder mithilfe der Standardoperatoren:
no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string  Wenn Sie sed ausführen, möchten Sie möglicherweise beachten, dass . mit jedem regulären Zeichen übereinstimmt Ausdrücke, daher wäre es korrekter, sie mit einem Backslash zu zitieren. Sie können auch einer sed -Instanz beide Befehle geben: sed -e "s/assemblyDB\.//" -e "s/\.las//". 
 Und dann for filename in $(find . -type f -name "assemblyDB.*.las"); do hat alle Probleme, die  beim Parsen von ls  hat, hauptsächlich die Tatsache, dass Leerzeichen und Platzhalter in Dateinamen es beschädigen. In ksh / Bash / zsh können Sie diese gesamte Schleife in der Shell ausführen: 
shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ... Kommentare
-  @Jesse_b, ja, aber wenn Ihre Shell <<<hat, hat sie wahrscheinlich auch${var/pat/repl}. Wenn Sie sed ausführen, können Sie beide Regeln einfach einersed-Instanz zuweisen:sed -e 's/assemblyDB\.//' -e 's/\.las//'
- Wollte nur weise auf UUOE hin;)
Antwort
 Anstelle von ${} Verwenden Sie Backticks ` [Die Schaltfläche unter Escape auf Ihrer Tastatur.] 
Kommentare
-  Bitte nicht ' Backticks nicht verwenden. Verwenden Sie die Befehlsersetzung. $( ... )
- Sie sind veraltet, schwer zu lesen, ' nisten nicht und können immer durch Ersetzen durch Klammerbefehle ersetzt werden. Außerdem sind sie in den meisten Markdown-Sprachen schwer in Inline-Codeblöcke einzufügen 🙂
- Ja, das ist richtig. Aber in Bezug auf diese Frage, wo ist meine Antwort falsch gelaufen?
- Sie haben vorgeschlagen, Backticks zu verwenden.
-  @Jesse_b Es gibt ' viele Gründe, keine Backticks zu verwenden, aber die Unfähigkeit, sie zu verschachteln, ist nicht einer von ihnen: echo `echo \`echo hello\``. Ja, es erfordert ein Escapezeichen, aber das bedeutet nur, dass ' nicht so einfach zu verschachteln ist wie$(...), nicht dass es ' ist unmöglich.
Antwort
Befehlssubstitution (Zeile 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=$(ls $filename | sed "s/assemblyDB.//" | sed "s/.las//") echo $no done  entspricht, wie bereits erwähnt, (Zeile 3, keine ls) 
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=$(echo $filename | sed "s/assemblyDB.//" | sed "s/.las//") echo $no done oder kürzer (Zeile 4 weg, jetzt direkt echo)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done und der Befehl sed kann reduziert werden bis (Zeile 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done oder extrahieren Sie den Mittelteil mit sed: (noch Zeile 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done Jetzt Find-Iterator statt For-Iterator: (Zeile 1 bis 3, 4 weg)
find . -type f -name "assemblyDB.*.las" -printf "%f\n" -exec sh -c " echo {} | sed -r "s/.*assemblyDB.(.*).las/\1/"" ";" assemblyDB.11.las 11 assemblyDB.9.las 9 assemblyDB.10.las 10 Wenn Ihre Dateinamen in sind In einer solchen oder einer ähnlichen Reihenfolge funktioniert möglicherweise auch Folgendes:
for i in {8..12} ; do ls assemblyDB.$i.las && echo $i ; done 2>/dev/null assemblyDB.9.las 9 assemblyDB.10.las 10 assemblyDB.11.las 11 (8 und 12 enthalten, um fehlende Dateien in der Sequenz zu demonstrieren).