Bin*_*abu 9 shell shell-script rename files
我需要交换两个文件(file和file_1)的文件名。我正在使用以下代码。
mv file .phfile
mv file_1 file
mv .phfile file
Run Code Online (Sandbox Code Playgroud)
这有效但非常有问题,有时甚至会导致数据丢失。有一个更好的方法吗?
虽然有点晚了,但您可以使用或\xe2\x80\x94在新版和旧版 Linux 中自动名称交换文件,这两个命令在所有主要 Linux 发行版中都可用 \xe2\x80\x94 到JITtccgcc自己的低级版本使用正确的内核系统调用的工具并使用它。无需第三方工具:
swapname() {\n tcc -run - "$@" <<"CODE"\n #include <unistd.h>\n #include <fcntl.h> \n #include <stdio.h>\n #include <sys/syscall.h>\n \n // Ubuntu 18.04 does not define RENAME_EXCHANGE\n // Value obtained manually from \'/usr/include/linux/fs.h\'\n // You should switch to RENAME_EXCHANGE on modern systems\n // Just remove the following line, then remove the `local_`\n // prefix where it appears later in this function.\n int local_RENAME_EXCHANGE = (1 << 1);\n \n int main(int argc, char **argv) {\n if (argc != 3) { \n fprintf(stderr, "Error: Could not swap names. Usage: %s PATH1 PATH2\\n", argv[0]);\n return 2; \n }\n int r = syscall(\n SYS_renameat2,\n AT_FDCWD, argv[1],\n AT_FDCWD, argv[2], \n local_RENAME_EXCHANGE\n );\n if (r < 0) {\n perror("Error: Could not swap names");\n return 1;\n }\n else return 0;\n }\nCODE\n} \nRun Code Online (Sandbox Code Playgroud)\n按以下方式运行此 bash 函数将干净且原子地交换文件名:
\nswapname "/path/to/file-1" "/path/to/file-2"\nRun Code Online (Sandbox Code Playgroud)\n请注意,renameat2withRENAME_EXCHANGE可能要求两个文件位于同一文件系统安装点下。请参阅手册页中的错误部分renameat2(即rename(2) ) 的错误部分以获取更多信息。
如果您更喜欢使用gcc而不是tcc,只需删除以tcc -run ...并在其位置添加以下行:
( EXEC="$(mktemp)" && gcc -x c - -o "$EXEC" && "$EXEC" "$@"; rm "$EXEC" ) <<"CODE" \nRun Code Online (Sandbox Code Playgroud)\n
在传统的 Unix 系统中没有交换文件的低级方法,因此您需要使用一个中间临时名称。为了健壮性,确保临时名称不会被任何其他程序使用(所以使用mktemp),并且它与文件之一位于同一文件系统上(否则文件将被不必要地复制而不是被重命名)。
swap_files () {
tmp_name=$(TMPDIR=$(dirname -- "$1") mktemp) &&
mv -f -- "$1" "$tmp_name" &&
mv -f -- "$2" "$1" &&
mv -f -- "$tmp_name" "$2"
}
swap_files file file_1
Run Code Online (Sandbox Code Playgroud)
请注意,如果发生错误,第一个文件可能仍使用其临时名称,而第二个文件可能尚未移动,也可能尚未移动。如果您需要在中断和崩溃的情况下保持健壮性,那么具有两个临时名称的变体可能更容易从中恢复。
swap_files2 () {
tmp_dir1=$(TMPDIR=$(dirname -- "$1") mktemp -d .swap_files.XXXXXXXXXXXX) &&
tmp_dir2=$(TMPDIR=$(dirname -- "$2") mktemp -d .swap_files.XXXXXXXXXXXX) &&
mv -f -- "$1" "$tmp_dir1/" &&
mv -f -- "$2" "$tmp_dir2/" &&
mv -f -- "$tmp_dir1/"* "$1" &&
mv -f -- "$tmp_dir2/"* "$2" &&
rmdir -- "$tmp_dir1" "$tmp_dir2"
}
Run Code Online (Sandbox Code Playgroud)
如果.swap_files.????????????重新启动时出现临时目录,则意味着文件交换因电源故障而中断。请注意,其中一个文件可能已经移动到位,而另一个尚未移动到位,因此此处的代码不会处理所有情况,这取决于您想要哪种恢复。
现代 Linux 内核(自 3.15 起,于 2014 年 6 月发布)具有交换文件的系统调用:renameat2(…, RENAME_EXCHANGE). 但是,它似乎没有常用的命令行实用程序。甚至最近才添加了 glibc 支持(2.28,于 2018 年 8 月发布)。
这是我最终使用的:
file1=1stfile
file2=2ndfile
tempdir="$(mktemp -d)"
mv "$file1" "$tempdir/tmpfile" &&
mv "$file2" "$file1" &&
mv "$tempdir/tmpfile" "$file2" &&
rm -rf "$tempdir"
Run Code Online (Sandbox Code Playgroud)