find 명령의 변수 및 추가 쉘 질문

find 명령의 변수 및 추가 쉘 질문

중복 가능성:
파일 및 디렉터리의 이름을 반복적으로 바꿉니다.

나는 다음 스크립트를 작성했습니다.

#!/bin/bash
SAVEIFS=$IFS
alias export='export'
IFS=$(echo -en "\n\b")

          find $1 -name "*" -a -type f -exec sh -c let  len=`expr length {}` \;  -exec  sh -c let  str=`expr substr {} 1 len-3` \; -exec ffmpeg -y -i {}  $str.mp3 \;

# restore $IFS
unalias export
IFS=$SAVEIFS

질문:

여러 셸에서 변수를 다른 셸로 내보낼 수 없다는 것을 알고 있으므로 다음이 필요합니다.

  1. 변수 사용

  2. 실행 쉘을 사용하지 마십시오

그럼 어떻게 해야 하나요?

다음 스크립트를 실행할 때:

find $1 -name "*" -a -type f -exec let  len=`expr length {}` \;  -exec let  str=`expr substr {} 1 len-3` \; -exec ffmpeg -y -i {}  $str.mp3 \; 
# Note : above script doesn't has 'sh -c' 

다음 오류가 발생합니다.

find: `let': No such file or directory

내보내기, 삭제export 또는 let으로 테스트했는데 -exec 내장 셸 명령에서 잘못된 점을 발견했습니다....!

어떤 아이디어가 있나요? ? ? ?

답변1

주의해야 할 몇 가지 사항이 있습니다.

  • 큰따옴표는 변수의 내용이 셸에서 해석되지 않도록 보호합니다. IFS에는 기본적으로 "space+tab+newline"이 포함될 수 있으므로 NEWIFS=IFSNEWIFS에 아무것도 넣지 못할 수도 있습니다.

    SAVEIFS="$IFS"
    ...
    IFS="$(echo -en "\n\b")"   
    #yes, you can have " inside $( ... ) : the shell will gladly interpret them by
    # order of depth inside the $() construct. 
    # A big advantage over using backquotes where it would get mixed up and almost unreadable
    ...
    IFS="$SAVEIFS"
    
  • 변수 이름으로 예약어를 사용하지 마십시오( for let등을 피하십시오). 또한 많은 "공통" 변수 이름(예: 등)도 피 LINES하십시오 COLUMNS.

    • export왜 별명인가 export? 쉘이 오래되었거나 기껏해야 쓸모가 없다면 이는 루프를 생성하는 좋은 방법처럼 보입니다.

    • 정밀도는 -name *로 끝나는 모든 것을 피한다는 의미입니다 ..

    • -exec sh .... 이는 서브쉘에서 시작됩니다 sh. sh가 호출 쉘로 종료되면 선언된 모든 변수는 손실됩니다.

다음과 같은 것이 필요합니다.

#!/bin/bash
for adirectory in "$@" ; do
    find "$adirectory" -type f -name '*.3gp' -print | while IFS= read -r wholeline ; do
       mylength=$(echo "$wholeline" | wc -c)  #Not needed, just kept as exemple of a way to achieve it
       myfilewithoutext="$(echo "$wholeline" | sed -e 's/.3gp$//' )"  
          #keeps only the filename without its ".3gp" or ".3GP" extension.
       ffmpeg -y -i "$wholeline"  "${myfilewithoutext}.mp3" > /dev/null   #?  please check if it works
    done #end of the find|while
done #end of the for looping on all the arguments passed to the script (dir names)

IFSwhile IFS= read -r wholeline ; do 통화 중에만 빈 문자열로 설정됩니다 read -r wholeline. 외부는 손길이 닿지 않았습니다. 명령 매개변수는 해당 값이 일시적으로 로 설정된 VAR="something" command parameters상태로 호출됩니다 . 여기서는 IFS를 아무것도 설정하지 않았습니다 . 여전히 한 줄씩 전달되고 비어 있으므로 전체 줄을 읽게 됩니다 .VARsomething''IFSread wholeline

답변2

의견에 따르면(*.3gp를 *.mp3로 변환):

for n in *.3gp; do
    ffmpeg -y -i "$n"  "${n%.3gp}.mp3"
done

Olivier의 의견에 따르면 파일 이름을 이스케이프할 필요가 없는 경우(즉, 공백이나 와일드카드가 포함되지 않은 경우) 하위 디렉터리의 파일에서도 작동하며 *.3gp. 또는 (bash에 넣어) 사용할 수 있습니다.$(find ...)\[?***/*.3gpshopt -s extglob.bashrc

관련 정보