我正在尝试编写一个bash脚本,对音乐文件进行一些处理。到目前为止,这是脚本:
#!/bin/bash
SAVEIFS=$IFS
IFS=printf"\n\0"
find `pwd` -iname "*.mp3" -o -iname "*.flac" | while read f
do
echo "$f"
$arr=($(f))
exiftool "${arr[@]}"
done
IFS=$SAVEIFS
这失败了:
[johnd:/tmp/tunes] 2 $ ./test.sh
./test.sh: line 9: syntax error near unexpected token `$(f)'
./test.sh: line 9: ` $arr=($(f))'
[johnd:/tmp/tunes] 2 $
我尝试了许多不同的咒语,但都没有奏效。底线是我正在尝试调用命令exiftool
,该命令的一个参数是一个可能包含空格的文件名。上面我试图将文件名$f
分配给一个数组并将该数组传递给exiftool
,但我在构造数组时遇到了麻烦。
当前的问题是,我该如何构建这个数组?但更深层次的问题是,如何从bash脚本中调用带有可能包含空格的参数的外部命令?
答案 0 :(得分:5)
你实际上确实拥有call-with-possible-space-containing-arguments语法(program "${args[@]}"
)。但是有几个问题。
首先,$(foo)
执行命令。如果您想要变量的值,请使用$foo
或${foo}
。
其次,如果要将某些内容附加到数组上,则语法为array+=(value)
(或者,如果它不起作用,array=("${array[@]}" value)
)。
第三,请使用\0
分隔文件名。换行符都很好,但文件名可以包含换行符。
第四,read
接受开关-d
,它可以与空字符串''
一起使用,以指定\0
作为分隔符。这样就无需使用IFS
。
第五,在管道进入while
循环时要小心 - 这会导致循环在子shell中执行,防止其中的变量赋值在外部生效。然而,有一种方法可以解决这个问题 - 使用流程替换(command | while ... done
)而不是管道(while ... done < <(command)
)。
第六,观察您的流程替换 - 当$(pwd)
执行时,不需要使用.
作为命令的参数。 (或者如果你真的必须有完整路径,请尝试引用pwd
电话。)
脚本,修订:
while read -r -d '' f; do
echo "$f" # For debugging?
arr+=("$f")
done < <(find . -iname "*.mp3" -o -iname "*.flac" -print0)
exiftool "${arr[@]}"
利用find
的全部功能:
find . -iname "*.mp3" -o -iname "*.flac" -exec exiftool {} +
# Much shorter!
所以你需要保存exiftool
的输出,操纵它,然后复制东西?试试这个:
while read -r -d '' f; do
echo "$f" # For debugging?
arr+=("$f")
done < <(find . -iname "*.mp3" -o -iname "*.flac" -print0)
# Warning: somewhat misleading syntax highlighting ahead
newfilename="$(exiftool "${arr[@]}")"
newfilename="$(manipulate "$newfilename")"
cp -- "$some_old_filename" "$newfilename"
您可能需要更改最后一位 - 我从未使用exiftool
,所以我不确切知道您之后(或如何操作),但这应该是一个开始。
答案 1 :(得分:2)
你可以用bash做到这一点:
shopt -s globstar nullglob
a=( **/*.{mp3,flac} )
exiftool "${a[@]}"
这可能也有效:exiftool **/*.{mp3,flac}