我正在编写一个脚本,它接受路径作为参数并处理路径中的所有 .mkv 文件。该路径可以是绝对路径、相对路径,甚至是单个文件。但是,我仍然需要正在迭代的文件的绝对路径。
这是我到目前为止所做的:
#!/bin/bash
path=$1
if ! [ -e "$path" ]; then
path=$(pwd)
fi
find "$path" -type f -name '*.mkv' | sort | xargs realpath | while read file; do
echo "Processing $file"
done
当路径和/或文件中没有空格时,此方法有效,但因空格而失败。
正确的做法是什么?
答案1
和zsh
:
#! /bin/zsh -
for file (${${1-.}:P}/**/*.mkv(ND.))
print -r processing $file
${1-.}
就像在 Bourne shell 中一样,扩展为.
if$1
is not set (if$#
== 0; if 是一个糟糕的接口,而不是当$1
is 是一个不存在的文件时,因为这会让用户感到非常惊讶)${param:P}
扩展到realpath()
该扩展的 。无需对每个文件执行相同的操作,因为**/
不遵循符号链接并且.
限定符仅选择常规的文件,所以不是符号链接。**/
匹配任何级别的子目录N
用于 nullglob、D
dotglob、.
for 的Glob 限定符常规的仅有的。
答案2
您可以预处理路径本身而不是所有文件:
find "$(realpath -- "$path")" -type f -name '*.mkv' -exec printf 'Processing %s\n' {} +
替换printf
为您实际想要对文件执行的任何操作。+
表示每次调用可以处理多个文件;如果不是这种情况,请改用\;
。
答案3
同意斯蒂芬的观点,总是更喜欢-exec
尝试对输出进行后处理find
。如果确实需要,请始终使用-print0
允许明确的文件名分隔;大多数从输入中使用文件名的工具都支持某种--null
, --zero
/-z
或-0
标志,以使它们将输入解释为以 0 字节分隔。
就你而言,我可能更喜欢 zsh,但假设你想坚持使用 bash,你可以做同样的事情而不会出现任何问题。您可以省略sort
,因为无论如何,通配符都是按字母顺序排列的。你可以省略find
,因为 bash 也可以进行递归通配(zsh 也可以在通配时限制文件类型,在 bash 中我们实际上需要测试-f
文件性),并且你可以省略,xargs
因为你正在处理一个文件无论如何,一次:
#!/bin/bash
# Fail when something goes wrong!
set -e
# enable recursive globs, and don't fail when there's nothing there
shopt -s globstar
shopt -s dotglob
shopt -s nullglob
inpath="$1"
if ! [ -e "${inpath}" ]; then
inpath="$(pwd)"
fi
for file in "${inpath}/**/*.mkv"; do
# check whether regular file, skip if not
[ -f "${file}" ] || continue
fullpath="$(realpath -- "${file}")"
echo "Processing ${fullpath}" # Could / might prefer to use printf here instead
done
你能以不同的方式对事物进行排序,以防默认排序确实不是您所需要的。你需要更换
for file in "${inpath}/**/*.mkv"; do
类似的东西
unsorted=( ${inpath}/**/*.mkv )
readarray -d '' -t sorted_files < \
<(printf '%s\0' "${unsorted[@]}" \
| sort -z --whateveroptions \
)
for file in "${sorted_files[@]}" ; do
readarray
具有-d
将分隔符设置为传递的字符串的选项;传递空字符串会使其使用零字节作为分隔符。readarray
的-t
修剪(我们在这里不需要它,但我发现它是一个安全的默认值),sort -z
使用零字节作为分隔符。"${arrayname[@]}"
扩展为该数组中元素的可迭代列表,但即使元素中包含空格和换行符,也可以安全使用。
在 zsh 中,您还可以对通过通配找到的文件进行排序。尽可能使用 zsh。