Otrzymałem następujący błąd:
./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution a to jest skrypt:
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"} echo $no done Komentarze
- Co próbujesz osiągnąć za pomocą aparatu ortodontycznego? Cytuj również swoje zmienne.
- Zobacz Dlaczego pętla wokół wyjścia find ' jest niewłaściwa? >
Odpowiedź
 ${ ... } (nawiasy klamrowe) oznacza kilka rodzaje  rozwijania parametrów , z których najprostszym jest po prostu rozszerzenie wartości zmiennej. Rzeczy wewnątrz nawiasów klamrowych w twoim kodzie to nie „ta poprawna nazwa parametru, ani żadne inne rozwinięcie, więc powłoka narzeka. 
 Wydaje się, że chcesz zamiast tego podstawiać komendy, w tym celu składnia to $( ... ) (zwykły nawias). 
 Ponadto ls w ls $filename | sed... wydaje się trochę niepotrzebne, zmienna rozwija się do nazwy pliku i ls po prostu ją przekazuje. Zamiast tego możesz po prostu użyć echo "$filename" | sed .... 
To powiedziawszy, możesz wprowadzić te modyfikacje bezpośrednio w powłoce:
no="${filename/assemblyDB.}" # remove first match no="${no/.las}" lub używając standardowych operatorów:
no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string  Jeśli uruchomisz sed, możesz zauważyć, że . pasuje do dowolnego znaku w zwykłym wyrażeń, więc bardziej poprawne byłoby zacytowanie go z ukośnikiem odwrotnym. Możesz także podać jednej sed instancji obu poleceń: sed -e "s/assemblyDB\.//" -e "s/\.las//". 
 A następnie for filename in $(find . -type f -name "assemblyDB.*.las"); do ma wszystkie problemy z  parsowaniem ls , głównie fakt, że białe znaki i symbole wieloznaczne w nazwach plików to załamują. W ksh / Bash / zsh możesz zrobić całą pętlę w powłoce: 
shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ... Komentarze
Odpowiedź
 Zamiast ${} użyj lewych znaczników ` [Przycisk poniżej Escape na klawiaturze.] 
Komentarze
-  Proszę nie ' nie używaj lewych apostrofów. Użyj podstawiania poleceń. $( ... )
- Są nieaktualne, trudne do odczytania, nie ' t zagnieżdżają się i nie mogą zawsze być zastępowane przez podstawianie poleceń w nawiasach. Dodatkowo trudno je umieścić w blokach kodu wbudowanego w większości języków przecen 🙂
- Tak, to prawda. Ale jeśli chodzi o to pytanie, gdzie moja odpowiedź poszła źle ??
- Zasugerowałeś użycie odwrotnych znaków.
-  @Jesse_b Istnieje ' wiele powodów, by nie używać grawisów, ale brak możliwości ich zagnieżdżenia nie jest jednym z nich: echo `echo \`echo hello\``. Tak, wymaga zmiany znaczenia, ale to po prostu oznacza, że ' nie jest tak łatwe do zagnieżdżenia jak$(...), a nie że jest niemożliwe.
Odpowiedź
Zastępowanie poleceń (wiersz 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  jest równoważne, jak już wspomniano, (line 3, no 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 lub krócej (linia 4 zniknęła, teraz bezpośrednie echo)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done i polecenie sed można zmniejszyć do (linia 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done lub może wyodrębnij środkową część za pomocą sed: (nadal linia 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done teraz znajdź-iterator zamiast for-iterator: (linie od 1 do 3, 4 zniknęły)
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 Jeśli twoje nazwy plików są w w takiej lub podobnej kolejności może działać również następująca:
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 (w tym 8 i 12, aby zademonstrować brakujące pliki w sekwencji).
<<<, prawdopodobnie ma też${var/pat/repl}. Jeśli uruchomisz seda, możesz po prostu przypisać obie reguły do jednejsedinstancji:sed -e 's/assemblyDB\.//' -e 's/\.las//'