“文件名太长” 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 11:18:26  来源:igfitidea点击:

"filename too long" bash mv command old files

bashshellunixmv

提问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 lscommand.

如果您的文件名中包含空格,那么您在解析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 basharrays, the statcommand, printf, sort -z, sed -z. Or you should simply outlaw filenames with spaces; it is probably easier.

两个带有空格的漂亮文件名。他们造成快乐的地狱。我将假设您使用的是 Linux 或类似的东西。您需要使用bash数组、stat命令、printfsort -zsed -z。或者你应该简单地取缔带有空格的文件名;这可能更容易。

names=( * )

The array namescontains 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 "%s
ls -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 forloop 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 sortcommand sorts the 'lines' numerically, assuming the lines are terminated by null bytes because of the -zoption, and places the most recent file names first. The sedcommand prints the first 30 'lines' (file names) only; the trcommand 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 sedand sortsupport the (non-standard) -zoption to process null-terminated input 'lines' — that means systems using GNU sedand sort(even BSD sedas found on Mac OS X does not, though the Mac OS X sortis GNU sortand does support -z).

代码工作甚至用含有换行符的文件名,但只能在系统中sedsort支持(非标准)-z选项来处理空终止输入“线” - ,采用GNU装置系统sedsort(甚至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 需要。