当文件名中有空格时,来自 shell 脚本的动态 mv 命令似乎不起作用
Dynamic mv command from shell script doesn't appear to be working when spaces are in the file names
我已经搜索了几个小时了,但似乎找不到这个问题的答案。我正在尝试在 FreeNAS 11 jail (freebsd) 中创建一个 shell 脚本,它将把一些文件移动到一个子文件夹中。我让它正确获取路径,但是当需要移动文件时,它不起作用(当文件名包含空格时)。
#!/bin/sh
# Primary dir to scan
SRC_DIR=/mnt/transcode/batch/
WORKING_DIR="${SRC_DIR}working/"
for FILE in $SRC_DIR*
do
# only run against files...
if test -f "${FILE}"
then
#FILE_NAME=$(basename "$FILE" | sed 's/ /\ /g') # replace spaces with escaped space
#mv "$SRC_DIR""$FILE_NAME" "$WORKING_DIR""$FILE_NAME"
#mv $SRC_DIR$FILE_NAME $WORKING_DIR$FILE_NAME
FILE_NAME=$(basename "$FILE")
mv \""$SRC_DIR""$FILE_NAME"\" \""$WORKING_DIR""$FILE_NAME"\" #wrap each parameter in double quotes
# copying this output back into terminal works
#echo mv \""$SRC_DIR""$FILE_NAME"\" \""$WORKING_DIR""$FILE_NAME"\"
fi
done
上面的代码还包含一些我也尝试过的额外内容。
我在 运行 脚本
时收到以下消息
mv: rename "/mnt/transcode/batch/REDACTED FILE NAME.mkv" to "/mnt/transcode/batch/working/REDACTED FILE NAME.mkv": No such file or directory
有趣的是,当我获取 echo mv \""$SRC_DIR""$FILE_NAME"\" \""$WORKING_DIR""$FILE_NAME"\"
的输出并将其粘贴回终端时,它会完美地执行。
我是 运行 通过 SSH 以 root 用户身份。目标文件夹权限为 drwxrwxr-x+
我是 运行 我的脚本,通过 ./test.sh
(作为 root 用户)
还有其他方法吗,还是我的脚本有问题?
感谢任何帮助。
PS 我的监狱里没有 /bin/bash,不确定这是否有影响。
--编辑--
这是我要执行的(希望)最终代码:
#!/bin/sh
# Primary dir to scan
SRC_DIR=/mnt/transcode/batch/
DEST_DIR="${SRC_DIR}converted/"
WORKING_DIR="${SRC_DIR}working/"
DONE_DIR="${SRC_DIR}orginal/"
# only get files, not directories
#for FILE in `ls -p $SRC_DIR | grep -v /`
for FILE in $SRC_DIR*
do
# only run against files...
if test -f "${FILE}"
then
FILE_NAME=$(basename "$FILE" | sed 's/ /\ /g')
# move the file to the working dir
mv $SRC_DIR$FILE_NAME $WORKING_DIR$FILE_NAME
# vars for later
MEDIA_FILE=$WORKING_DIR$FILE_NAME
# Get some into about the current file
AUDIO_CODEC="$(ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of csv=s=x:p=0 $MEDIA_FILE)"
MEDIA_INFO="$(ffprobe -v error -select_streams v:0 -show_entries stream=height,width -of csv=s=x:p=0 $MEDIA_FILE)"
VIDEO_HEIGHT="$(echo "$MEDIA_INFO" | cut -d 'x' -f2)"
VIDEO_WIDTH="$(echo "$MEDIA_INFO" | cut -d 'x' -f1)"
# start up handbrake
HandBrakeCLI -i $WORKING_DIR$FILE_NAME -o $DEST_DIR${FILE_NAME%.*}.mkv -f av_mkv -m -e x264 -q 22 --vfr --audio-lang-list eng -E copy:$AUDIO_CODEC --crop 0:0:0:0 -w $VIDEO_WIDTH -l $VIDEO_HEIGHT --subtitle-lang-list eng
# move the file to the done dir
mv $WORKING_DIR$FILE_NAME $DONE_DIR$FILE_NAME
fi
done
最终目标是将单个文件移动到工作目录,同时正在转码,然后将其移出完成文件夹。
问题是您在文件名中添加了额外的引号。
mv \"foo\" bar
尝试重命名字面上称为 "foo"
(包括引号)的文件。
另外,不要使用 ALL_UPPERCASE
作为变量。 ALL_UPPERCASE
由系统使用(例如 HOME
)或 shell 本身(例如 RANDOM
、PWD
)。
我会这样做:
src_dir=/mnt/transcode/batch
working_dir="$src_dir/working"
for file in "$src_dir"/*; do
# only run against files...
if test -f "$file"; then
mv -- "$file" "$working_dir/"
fi
done
您可以mv
直接进入目录,无需先提取基本名称。
未经测试,但这是您脚本的其余部分。我添加了遗漏的引号,删除了奇怪的反斜杠添加等。
#!/bin/sh
# Primary dir to scan
src_dir=/mnt/transcode/batch
dest_dir="$src_dir/converted"
working_dir="$src_dir/working"
done_dir="$src_dir/orginal"
for src_file in "$src_dir"/*; do
if test -f "${src_file}"; then
basename="${src_file##*/}"
working_file="$working_dir/$basename"
# move the file to the working dir
mv -- "$src_file" "$working_file"
# Get some into about the current file
audio_codec="$(ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of csv=s=x:p=0 "$working_file")"
media_info="$(ffprobe -v error -select_streams v:0 -show_entries stream=height,width -of csv=s=x:p=0 "$working_file")"
video_height="${media_info#*x}"
video_width="${media_info%%x*}"
# start up handbrake
HandBrakeCLI -i "$working_file" -o "$dest_dir/${basename%.*}.mkv" -f av_mkv -m -e x264 -q 22 --vfr --audio-lang-list eng -E copy:"$audio_codec" --crop 0:0:0:0 -w "$video_width" -l "$video_height" --subtitle-lang-list eng
# move the file to the done dir
mv -- "$working_file" "$done_dir/"
fi
done
我已经搜索了几个小时了,但似乎找不到这个问题的答案。我正在尝试在 FreeNAS 11 jail (freebsd) 中创建一个 shell 脚本,它将把一些文件移动到一个子文件夹中。我让它正确获取路径,但是当需要移动文件时,它不起作用(当文件名包含空格时)。
#!/bin/sh
# Primary dir to scan
SRC_DIR=/mnt/transcode/batch/
WORKING_DIR="${SRC_DIR}working/"
for FILE in $SRC_DIR*
do
# only run against files...
if test -f "${FILE}"
then
#FILE_NAME=$(basename "$FILE" | sed 's/ /\ /g') # replace spaces with escaped space
#mv "$SRC_DIR""$FILE_NAME" "$WORKING_DIR""$FILE_NAME"
#mv $SRC_DIR$FILE_NAME $WORKING_DIR$FILE_NAME
FILE_NAME=$(basename "$FILE")
mv \""$SRC_DIR""$FILE_NAME"\" \""$WORKING_DIR""$FILE_NAME"\" #wrap each parameter in double quotes
# copying this output back into terminal works
#echo mv \""$SRC_DIR""$FILE_NAME"\" \""$WORKING_DIR""$FILE_NAME"\"
fi
done
上面的代码还包含一些我也尝试过的额外内容。
我在 运行 脚本
时收到以下消息mv: rename "/mnt/transcode/batch/REDACTED FILE NAME.mkv" to "/mnt/transcode/batch/working/REDACTED FILE NAME.mkv": No such file or directory
有趣的是,当我获取 echo mv \""$SRC_DIR""$FILE_NAME"\" \""$WORKING_DIR""$FILE_NAME"\"
的输出并将其粘贴回终端时,它会完美地执行。
我是 运行 通过 SSH 以 root 用户身份。目标文件夹权限为 drwxrwxr-x+
我是 运行 我的脚本,通过 ./test.sh
(作为 root 用户)
还有其他方法吗,还是我的脚本有问题?
感谢任何帮助。
PS 我的监狱里没有 /bin/bash,不确定这是否有影响。
--编辑--
这是我要执行的(希望)最终代码:
#!/bin/sh
# Primary dir to scan
SRC_DIR=/mnt/transcode/batch/
DEST_DIR="${SRC_DIR}converted/"
WORKING_DIR="${SRC_DIR}working/"
DONE_DIR="${SRC_DIR}orginal/"
# only get files, not directories
#for FILE in `ls -p $SRC_DIR | grep -v /`
for FILE in $SRC_DIR*
do
# only run against files...
if test -f "${FILE}"
then
FILE_NAME=$(basename "$FILE" | sed 's/ /\ /g')
# move the file to the working dir
mv $SRC_DIR$FILE_NAME $WORKING_DIR$FILE_NAME
# vars for later
MEDIA_FILE=$WORKING_DIR$FILE_NAME
# Get some into about the current file
AUDIO_CODEC="$(ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of csv=s=x:p=0 $MEDIA_FILE)"
MEDIA_INFO="$(ffprobe -v error -select_streams v:0 -show_entries stream=height,width -of csv=s=x:p=0 $MEDIA_FILE)"
VIDEO_HEIGHT="$(echo "$MEDIA_INFO" | cut -d 'x' -f2)"
VIDEO_WIDTH="$(echo "$MEDIA_INFO" | cut -d 'x' -f1)"
# start up handbrake
HandBrakeCLI -i $WORKING_DIR$FILE_NAME -o $DEST_DIR${FILE_NAME%.*}.mkv -f av_mkv -m -e x264 -q 22 --vfr --audio-lang-list eng -E copy:$AUDIO_CODEC --crop 0:0:0:0 -w $VIDEO_WIDTH -l $VIDEO_HEIGHT --subtitle-lang-list eng
# move the file to the done dir
mv $WORKING_DIR$FILE_NAME $DONE_DIR$FILE_NAME
fi
done
最终目标是将单个文件移动到工作目录,同时正在转码,然后将其移出完成文件夹。
问题是您在文件名中添加了额外的引号。
mv \"foo\" bar
尝试重命名字面上称为 "foo"
(包括引号)的文件。
另外,不要使用 ALL_UPPERCASE
作为变量。 ALL_UPPERCASE
由系统使用(例如 HOME
)或 shell 本身(例如 RANDOM
、PWD
)。
我会这样做:
src_dir=/mnt/transcode/batch
working_dir="$src_dir/working"
for file in "$src_dir"/*; do
# only run against files...
if test -f "$file"; then
mv -- "$file" "$working_dir/"
fi
done
您可以mv
直接进入目录,无需先提取基本名称。
未经测试,但这是您脚本的其余部分。我添加了遗漏的引号,删除了奇怪的反斜杠添加等。
#!/bin/sh
# Primary dir to scan
src_dir=/mnt/transcode/batch
dest_dir="$src_dir/converted"
working_dir="$src_dir/working"
done_dir="$src_dir/orginal"
for src_file in "$src_dir"/*; do
if test -f "${src_file}"; then
basename="${src_file##*/}"
working_file="$working_dir/$basename"
# move the file to the working dir
mv -- "$src_file" "$working_file"
# Get some into about the current file
audio_codec="$(ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of csv=s=x:p=0 "$working_file")"
media_info="$(ffprobe -v error -select_streams v:0 -show_entries stream=height,width -of csv=s=x:p=0 "$working_file")"
video_height="${media_info#*x}"
video_width="${media_info%%x*}"
# start up handbrake
HandBrakeCLI -i "$working_file" -o "$dest_dir/${basename%.*}.mkv" -f av_mkv -m -e x264 -q 22 --vfr --audio-lang-list eng -E copy:"$audio_codec" --crop 0:0:0:0 -w "$video_width" -l "$video_height" --subtitle-lang-list eng
# move the file to the done dir
mv -- "$working_file" "$done_dir/"
fi
done