find 命令中的变量和更多 shell 问题

find 命令中的变量和更多 shell 问题

可能的重复:
递归重命名文件和目录

我写了以下脚本:

#!/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

问题:

你知道当多个 shell 时你无法在其他 shell 中导出你的变量,所以我需要:

  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或deleteexport或let测试了它,我发现-exec内置shell命令有问题....!

你有什么主意吗????

答案1

你需要注意几件事

  • 双引号可保护变量的内容不被 shell 解释。 IFS 默认情况下可能包含“空格+制表符+换行符”,因此 :NEWIFS=IFS可能最终不会在 NEWIFS 中放置任何内容。

    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等。还要避免许多“常见”变量名,即LINESCOLUMNS等。

    • 为什么别名exportexport?如果 shell 很旧,或者充其量是无用的,那么看起来是创建循环的好方法。

    • 精确-name *意味着您避免任何以..

    • -exec sh .... 将在子 shell 中启动它 sh:一旦 sh 退出到调用 shell,您在其中声明的任何变量都将丢失。

你需要类似的东西:

#!/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将调用命令参数,其值VAR暂时设置为something。这里我们将 IFS 设置为'',即什么也不设置。它仍然会逐行传递,并且由于IFS是空的,整行最终都会被 读取read wholeline

答案2

根据评论(将 *.3gp 转换为 *.mp3):

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

根据奥利维尔的评论,如果文件名不需要转义(即它们不包含空格或通配符),也可以对子目录中的文件进行操作,*.3gp可以替换为。或者可以使用(在 bash 中,放入您的)。$(find ...)\[?***/*.3gpshopt -s extglob.bashrc

相关内容