我想迭代文件列表,而不关心文件名可能包含哪些字符,因此我使用由空字符分隔的列表。代码会更好地解释事情。
# Set IFS to the null character to hopefully change the for..in
# delimiter from the space character (sadly does not appear to work).
IFS=$'\0'
# Get null delimited list of files
filelist="`find /some/path -type f -print0`"
# Iterate through list of files
for file in $filelist ; do
# Arbitrary operations on $file here
done
以下代码在从文件读取时有效,但我需要从包含文本的变量中读取。
while read -d $'\0' line ; do
# Code here
done < /path/to/inputfile
执行此操作的首选方法是使用进程替换:
while IFS= read -r -d $'\0' file <&3; do
# Arbitrary operations on "$file" here
done 3< <(find /some/path -type f -print0)
如果您一心想以类似的方式解析 bash 变量,则可以这样做 只要列表不是 NUL 终止。
这是 bash var 保存制表符分隔字符串的示例:
$ var="$(echo -ne 'foo\tbar\tbaz\t')"
$ while IFS= read -r -d $'\t' line <&3; do
echo "#$line#"
done 3<<<"$var"
#foo#
#bar#
#baz#
将它们通过管道传输到
xargs -0
:
files="$( find ./ -iname 'file*' -print0 | xargs -0 )"
-0, --null Input items are terminated by a null character instead of by whitespace, and the quotes and backslash are not special (every character is taken literally).
使用
env -0
输出零字节的赋值。
env -0 | while IFS='' read -d '' line ; do
var=${line%%=*}
value=${line#*=}
echo "Variable '$var' has the value '$value'"
done
就可读性和可维护性而言,bash 函数可能更干净:
使用
MOV
将 MP4
文件转换为 ffmpeg
的示例(适用于包含空格和特殊字符的文件):
#!/usr/bin/env bash
do_convert () {
new_file="${1/.mov/.mp4}"
ffmpeg -i "$1" "$new_file" && rm "$1"
}
export -f do_convert # needed to make the function visible inside xargs
find . -iname '*.mov' -print0 | xargs -0 -I {} bash -c 'do_convert "{}"' _ {}
不适用于OP的问题,但如果您的输入是由
find
生成的,则无需通过xargs -0
进行管道传输,因为find
完全能够处理文件名中的非ascii字符和空格。如果你不关心可读性和可维护性,那么上面的命令可以简化为:
find . -type f -iname "*.mov" -exec bash -c 'ffmpeg -i "${1}" "${1%.*}.mp4" && rm "${1}"' _ {} \;
我尝试使用上面的bash示例,最后放弃了,并使用了Python,它第一次工作了。对我来说,事实证明,在外壳之外问题更简单。我知道这可能不是 bash 解决方案的主题,但无论如何我都会将其发布在这里,以防其他人想要替代方案。
import sh
import path
files = path.Path(".").files()
for x in files:
sh.cp("--reflink=always", x, "UUU00::%s"%(x.basename(),))
sh.cp("--reflink=always", x, "UUU01::%s"%(x.basename(),))