$ {ls …를 실행하는 잘못된 대체 | sed …} with bash

다음 오류가 발생했습니다.

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

댓글

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 개 포함)

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다