Answers:
这可以通过bash / ksh93 / zsh数组轻松完成:
a=(*)
cp -- "${a[@]: -4}" ~/
这适用于所有非隐藏文件名,即使它们包含空格,制表符,换行符或其他困难字符(假设当前目录中至少有4个非隐藏文件带有bash
)也是如此。
a=(*)
这将创建一个a
包含所有文件名的数组。bash返回的文件名按字母顺序排序。(我假设这就是您所说的“按文件名排序”。)
${a[@]: -4}
这将返回数组的最后四个元素a
(前提是该数组至少包含个带有的元素bash
)。
cp -- "${a[@]: -4}" ~/
这会将最后四个文件名复制到您的主目录。
这将仅将最后四个文件复制到主目录,并同时在字符串前a_
添加复制文件的名称:
a=(*)
for fname in "${a[@]: -4}"; do cp -- "$fname" ~/a_"$fname"; done
如果使用a=(./some_dir/*)
而不是a=(*)
,则存在目录附加到文件名的问题。一种解决方案是:
a=(./some_dir/*)
for f in "${a[@]: -4}"; do cp "$f" ~/a_"${f##*/}"; done
另一个解决方案是使用一个子shell并cd
进入该子shell 中的目录:
(cd ./some_dir && a=(*) && for f in "${a[@]: -4}"; do cp -- "$f" ~/a_"$f"; done)
子外壳程序完成后,外壳程序将我们返回到原始目录。
该问题要求“按文件名排序”的文件。Olivier Dulac在评论中指出,该顺序会因地区而异。如果重要的是要有独立于计算机设置的固定结果,则最好在a
定义数组时明确指定语言环境。例如:
LC_ALL=C a=(*)
您可以通过运行locale
命令来查找当前所在的语言环境。
如果您正在使用zsh
,则可以在括号中()
包含所谓的glob限定符的列表,这些限定符用于选择所需的文件。在你的情况下,那将是
cp *(On[1,4]) ~/
在此,On
文件名以相反的顺序按字母顺序排序,并且[1,4]
仅使用前4个。
通过使用选择仅纯文件(不包括目录,管道等).
,并通过附加--
到cp
命令以处理名称以-
正确开头的文件,您可以使此功能更强大:
cp -- *(.On[1,4]) ~
D
如果您还想考虑隐藏文件(点文件),请添加限定符:
cp -- *(D.On[1,4]) ~
*([-4,-1])
。
on
)按字母顺序排序是默认行为,因此无需指定,并且-
数字前面从底部开始计算文件名。
只要您认为外壳排序合适,就可以这样做:
set -- /path/to/source/dir/*
[ "$#" -le 4 ] || shift "$(($#-4))"
cp "$@" /path/to/target/dir
这与提供的bash
特定于阵列的解决方案非常相似,但应可移植到任何POSIX兼容的外壳中。关于这两种方法的一些注意事项:
重要的是您要带上您的cp
论点,cp --
或者您要获得一个.
圆点或/
每个名称的开头。如果您不这样做,则可能冒第一个参数前导-
破折号的危险,该破折号cp
可以解释为选项,并导致操作失败或导致意外结果。
set -- ./*
或array=(./*)
。使用这两种方法时,确保您要删除的arg数组中的项目数最少是很重要的-我在这里通过数学扩展来做到这一点。的shift
如果有在阿根廷阵中至少4项只发生-然后只转移那些远离第一ARGS,使4盈余..
set 1 2 3 4 5
情况下,它将转移1
,但在某种set 1 2 3
情况下,它将什么也不会转移。a=(1 2 3); echo "${a[@]: -4}"
打印空白行。如果要从一个目录复制到另一个目录,则可以使用pax
:
set -- /path/to/source/dir/*
[ "$#" -le 4 ] || shift "$(($#-4))"
pax -rws '|.*/|new_prefix|' "$@" /path/to/target/dir
...这将sed
在复制所有文件名时将-style替换应用于所有文件名。
如果只有文件且文件名不包含空格或换行符(并且您尚未修改$IFS
)或全局字符(或某些带有的某些实现的不可打印字符ls
),并且不以开头.
,则可以执行此操作:
cp -- $(ls | tail -n 4) ~/
a_
为所有四个文件添加前缀?我试过了echo "a_$(ls | tail -n 4)"
,但是它只是添加了第一个文件。
ls
输出被认为是错误的形式,因为它通常会严重失败,因为文件名不仅包含空格,而且还包含制表符,换行符或其他有效但“困难”的字符。
LC_ALL=C