可能的重复:
递归重命名文件和目录
我写了以下脚本:
#!/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 中导出你的变量,所以我需要:
使用变量
不要使用运行外壳
那么,我该怎么做呢?
当运行以下脚本时:
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
等。还要避免许多“常见”变量名,即LINES
、COLUMNS
等。为什么别名
export
为export
?如果 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)
IFS
while 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 ...)
\[?*
**/*.3gp
shopt -s extglob
.bashrc