다음 오류가 발생했습니다.
./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution
다음은 스크립트입니다.
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"} echo $no done
댓글
- 중괄호로 무엇을 달성하려고합니까? 또한 변수를 인용하십시오.
- Find '의 출력 불량 사례를 반복하는 이유는 무엇입니까?
Answer
${ ... }
(중괄호)는 여러 표시 일종의 매개 변수 확장 입니다. 가장 간단한 방법은 변수 값을 확장하는 것입니다. 코드에서 중괄호 안에있는 항목은 “유효한 매개 변수 이름 또는 다른 확장이 아니므로 쉘이 불평합니다.
대신 명령 대체를 원하는 것 같습니다. 그 대신 구문은 (일반 괄호).
또한 ls $filename | sed...
의 ls
도 약간 보입니다. 불필요합니다. 변수는 파일 이름으로 확장되고 ls
는 그냥 통과합니다. 대신 echo "$filename" | sed ...
를 사용할 수 있습니다.
즉, 이러한 수정은 셸에서 직접 수행 할 수 있습니다.
no="${filename/assemblyDB.}" # remove first match no="${no/.las}"
또는 표준 연산자를 사용하여 :
no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string
sed
를 실행하면 .
가 일반 문자와 일치한다는 점에 유의할 수 있습니다. 표현식이므로 백 슬래시로 인용하는 것이 더 정확합니다. 또한 하나의 sed
인스턴스에 두 명령을 모두 제공 할 수 있습니다. sed -e "s/assemblyDB\.//" -e "s/\.las//"
.
그리고 for filename in $(find . -type f -name "assemblyDB.*.las"); do
에는 ls 구문 분석 이 갖는 모든 문제가 있으며, 대부분 파일 이름의 공백과 와일드 카드로 인해 문제가 발생합니다. ksh / Bash / zsh에서는 셸에서 전체 루프를 수행 할 수 있습니다.
shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ...
댓글
- @Jesse_b, 예,하지만 셸에
<<<
가있는 경우${var/pat/repl}
도있을 수 있습니다. sed를 실행하면 하나의sed
인스턴스에 두 규칙을 모두 제공 할 수 있습니다.sed -e 's/assemblyDB\.//' -e 's/\.las//'
- 지적 UUOE;)
답변
${}
대신 백틱 사용 `
[키보드의 Escape 아래 버튼]
댓글
- 제발 ' 백틱을 사용하지 마십시오. 명령 대체를 사용하십시오.
$( ... )
- 오래되어 읽기 어렵고 중첩되지 않으며 ' 항상 은 괄호 명령 대체로 대체됩니다. 또한 대부분의 마크 다운 언어에서 인라인 코드 블록에 배치하기가 어렵습니다. 🙂
- 예, 맞습니다. 하지만이 질문과 관련하여 내 대답이 어디에서 잘못 되었습니까?
- 백틱을 사용하도록 제안하셨습니다.
- @Jesse_b 거기 ' 많이 백틱을 사용하지 않는 이유가 있지만 중첩 할 수없는 이유는
echo `echo \`echo hello\``
입니다. 예, 이스케이프가 필요하지만 ' 중첩이$(...)
만큼 쉽지는 않습니다. ' 불가능합니다.
답변
명령 대체 (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
이미 지적했듯이 (3 행, 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
또는 더 짧게 (4 번 줄이 사라졌고 이제 직접 에코 됨)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done
그리고 sed 명령을 줄일 수 있습니다. to (line 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done
또는 sed : (스틸 라인 3)으로 중간 부분 추출
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done
이제 for-iterator 대신 find-iterator : (라인 1에서 3, 4가 사라짐)
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
파일 이름이 다음과 같은 순서로도 작동 할 수 있습니다.
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 개 및 12 개 포함)