如果存在同名的现有文件,如何为文件生成新名称?在桌面环境中,通过在文件名末尾附加数字来生成新名称,但是如何从命令行完成此操作?
我正在使用 Android 操作系统和 Busybox。
答案1
假设您有 POSIX shell,您可以执行以下操作:
mv() {
eval "DEST=\${$#}" #The destination is the last positional parameter
if [ -e "$DEST" ] && ! [ -d "$DEST" ];then
PREFIX=${DEST%.*}
COUNT=1
EXT=${DEST##*.}
args= i=1
while [ $i -lt $# ]; do args="$args \"\${$i}\"" i=$((i+1)); done
DEST="$NAME-"$(printf "%03d" $COUNT)".$EXT"
while [ -e "$DEST" ];do
COUNT=$((COUNT+1))
DEST="$NAME-"$(printf "%03d" $COUNT)".$EXT"
done
eval "command mv $args \"\$DEST\""
else
command mv "$@"
fi
}
如何使用这个
这是一个函数,因此请将其保存在您的文件中~/.bashrc
并像正常的mv
.
这是做什么的
- 将原始可执行文件的路径存储
mv
在MV
变量中 - 获取调用它的最后一个参数到变量中
DEST
- 如果
DEST
存在并且不是目录,则此函数假定您的重命名正在尝试破坏文件 - 然后,它提取最终名称的前缀(最终名称之前的任何内容
.
,标记扩展名)、扩展名(最终名称之后的任何内容.
)、计数(如果有;最终名称之后的前缀中的任何内容-
)。 - 如果未找到计数,则提取的计数将设置为零,否则将设置为上一步中找到的计数。
- 当前计数增加
- 然后,该函数使用所有原始参数(开关+文件名)减去最后一个参数来调用自身,并添加新文件名而不是原始调用中的最后一个参数。新名称是旧名称,但在扩展名之前添加了 3 位计数器(零填充)。
- 该函数是递归的,因为如果你说它
mv a.txt b.txt
会首先尝试mv a.txt b-001.txt
.下一个mv
调用也必须是函数本身,因为如果b-001.txt
也存在,我们希望继续递增计数器,直到找到不存在的新文件名。 - 如果最后一个参数不存在或者是一个目录,则
mv
使用原始参数调用原始可执行文件。
注意事项
- 您可以重复尝试破坏现有文件的次数取决于计数器的长度(在本例中为 999 次)。您可以选择包含文件系统上 inode 限制的数字,以确保只要您能够创建文件,它就可以工作。
- 如果您尝试破坏名称类似于 的文件
foo-001.txt
,它将被移动到foo-001-001.txt
.
笔记
- 要更改命名模式,请将语句
3
中的 更改printf
为您喜欢的任何内容。 - 这段代码已经测试过
- 这是非常简单的,我确信在某些边缘情况下它会严重失败。如果您发现任何问题,我很乐意为您尝试修复它们。同时,请勿在生产机器上尝试此操作。
答案2
我通常使用该工具mktemp
来创建可靠的临时文件。它默认创建文件,但也可以通过其-d
开关创建目录。
例子
以下是如何为当前目录中的文件创建一些临时名称。
$ mktemp somefile.XXXXX
somefile.kiDad
$ mktemp somefile.XXXX
somefile.MrSW
$ mktemp someotherfile.XXXXXXXXXXX
someotherfile.Um4aXKrt3lv
这将为您创建文件。
参考
答案3
这是 Joseph R 脚本的替代方案,没有任何警告!它将在路径名后附加一个数字后缀(路径可以是目录或文件),递增后缀值,直到找到尚不存在的后缀。其他实用程序例如logrotate
使用类似的模式,但旋转所有现有副本,以便新副本始终具有“0”后缀。因为这不是那种意义上的轮换,所以我将其称为dotmv
.请记住,这file.0
将是最老的复制。
例如:
dotmv somefile.txt
重命名somefile.txt
somefile.txt.0
,除非后者存在,在这种情况下它将是somefile.txt.1
,依此类推。您可以列出多个文件(dotmv this that "the other thing"
等等),所有文件都将被点移动。
我相信这是 POSIX 兼容的——它set -o posix
在 bash 上运行(但这是一个可疑的测试)。我还用 android (jelly bean 4.2.1) shell 进行了测试,它可以在那里工作。但是,在 Android 上,您需要按照指示更改 shebang 或运行它sh dotmv
- 除非您有 root 设备,否则您无论如何都会这样做,因为否则无法使脚本可执行。更改 shebang 将允许您使用exec dotmv
.
#!/bin/sh
# On android change that to /system/bin/sh.
# Validate arguments
if [ $# -lt 1 ]; then
echo "A list of one or more paths is required."
exit 1
fi
# Checks if a path exists and can be moved.
checkPath () {
if [ ! -e "$1" ]; then
echo "'$1' does not exist."
return 1;
fi
if [ ! -w "$1" ]; then
echo "Cannot move '$1', permission denied."
return 1;
fi
return 0;
}
# Finds a new path with numerical suffix.
getName () {
suf=0;
while [ -e "$1.$suf" ]
do let suf+=1
done
Dest=$1.$suf
}
# Loop through arguments -- use quotes to allow spaces in paths.
while (($#)); do
Src=$1
Dest=$1
shift
checkPath "$Src"
if [ $? -eq 0 ]; then
getName "$Src"
mv "$Src" "$Dest"
fi
done
希望这里的逻辑非常简单。这可以用 python、C 或任何其他带有文件 I/O 的图灵完备过程语言来实现。