“文件名太长” bash mv 命令旧文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25696474/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"filename too long" bash mv command old files
提问by user3776934
#! /bin/sh -
cd /PHOTAN || exit
fn=$(ls -t | tail -n -30)
mv -f -- "${fn}" /old
all I want todo is keep most recent 30 files... but cant get past the mv "File name too long" problem
我想要做的就是保留最近的 30 个文件......但无法解决 mv“文件名太长”问题
please help'
请帮忙'
回答by Jonathan Leffler
The notation "${fn}"
adds all the file names into a single argument string, separated by spaces. Just for once, assuming you don't have to worry about file names with spaces in them, you need:
该表示法"${fn}"
将所有文件名添加到单个参数字符串中,以空格分隔。就这一次,假设您不必担心文件名中包含空格,您需要:
mv -f -- ${fn} /old
If you have file names with spaces in them, then you've got problems starting with parsing the output of the ls
command.
如果您的文件名中包含空格,那么您在解析ls
命令的输出时就会遇到问题。
But what if you do have to worry about spaces in your filenames?
但是,如果您确实必须担心文件名中的空格怎么办?
Then, as I stated, you have major problems, starting with the issues of parsing the output of ls
.
然后,正如我所说,您遇到了主要问题,首先是解析ls
.
$ echo > 'a b'
$ echo > ' c d '
$
Two nice file names with spaces in them. They cause merry hell. I'm about to assume you're on Linux or something similar enough. You need to use bash
arrays, the stat
command, printf
, sort -z
, sed -z
. Or you should simply outlaw filenames with spaces; it is probably easier.
两个带有空格的漂亮文件名。他们造成快乐的地狱。我将假设您使用的是 Linux 或类似的东西。您需要使用bash
数组、stat
命令、printf
、sort -z
、sed -z
。或者你应该简单地取缔带有空格的文件名;这可能更容易。
names=( * )
The array names
contains each file name as a separate array element, leading and trailing and embedded blanks all handled correctly.
该数组names
包含每个文件名作为单独的数组元素,前导和尾随以及嵌入的空白都得到了正确处理。
names=( * )
for file in "${names[@]}"
do printf "%sls -t |
tail -30 |
{
list=()
while IFS='' read -r file
do list+=( "$file" )
done
mv -f -- "${list[@]}" /old
}
" "$(stat -c '%Y' "$file") $file"
done |
sort -nzr |
sed -nze '1,30s/^[0-9][0-9]* //p' |
tr '##代码##' '\n'
The for
loop evaluates the modification time of each file separately, and combines the modification time, a space, and the file name into a single string followed by a null byte to mark the end of the string. The sort
command sorts the 'lines' numerically, assuming the lines are terminated by null bytes because of the -z
option, and places the most recent file names first. The sed
command prints the first 30 'lines' (file names) only; the tr
command replaces null bytes with newlines (but in doing so, loses the identity of file name boundaries).
的for
循环分别计算每个文件的修改时间,和结合了修改时间,空间,和文件名成一个字符串后跟一个空字节来标记串的结束。该sort
命令以数字方式对“行”进行排序,假设行因该-z
选项而以空字节终止,并将最近的文件名放在最前面。该sed
命令仅打印前 30 个“行”(文件名);该tr
命令用换行符替换空字节(但这样做会丢失文件名边界的标识)。
The code works even with file names containing newlines, but only on systems where sed
and sort
support the (non-standard) -z
option to process null-terminated input 'lines' — that means systems using GNU sed
and sort
(even BSD sed
as found on Mac OS X does not, though the Mac OS X sort
is GNU sort
and does support -z
).
代码工作甚至用含有换行符的文件名,但只能在系统中sed
和sort
支持(非标准)-z
选项来处理空终止输入“线” - ,采用GNU装置系统sed
和sort
(甚至BSDsed
如Mac OS X上发现的确不是,尽管 Mac OS Xsort
是 GNUsort
并且确实支持-z
)。
Ugh! The shell was designed for spaces to appear between and not within file names.
啊! shell 被设计为空格出现在文件名之间而不是出现在文件名内。
As noted by BroSlowin a comment, if you assume 'no newlines in filenames', then the code can be simpler and more nearly portable — but it is still tricky:
正如BroSlow在评论中指出的那样,如果你假设“文件名中没有换行符”,那么代码可以更简单,更接近可移植性——但它仍然很棘手:
##代码##The IFS=''
is needed so that leading and trailing spaces in filenames are preserved (and tabs, too).
的IFS=''
需要,这样的文件名开头和结尾的空格都被保留(和标签,太)。
I note in passing that the Korn shell would not require the braces but Bash does.
我顺便指出,Korn shell 不需要大括号,但 Bash 需要。