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//'