我有一个文件列表
-rw-rw-r-- 1 t t 24813 Oct 23 2002 fig8_21.gif
-rw-rw-r-- 1 t t 2259 Oct 23 2002 fig8_21t.gif
-rw-rw-r-- 1 t t 35331 Oct 23 2002 fig8_23.gif
-rw-rw-r-- 1 t t 2610 Oct 23 2002 fig8_23t.gif
-rw-rw-r-- 1 t t 19970 Oct 23 2002 fig8_24.gif
-rw-rw-r-- 1 t t 2019 Oct 23 2002 fig8_24t.gif
-rw-rw-r-- 1 t t 54623 Oct 23 2002 fig8_3.gif
-rw-rw-r-- 1 t t 3657 Oct 23 2002 fig8_3t.gif
-rw-rw-r-- 1 t t 35861 Oct 23 2002 fig8_4.gif
-rw-rw-r-- 1 t t 2344 Oct 23 2002 fig8_4t.gif
我想<...>t.gif
用<...>.gif
例如 copy fig8_4.gif
to overwrite进行覆盖fig8_4t.gif
。
我首先<...>t.gif
通过 找到这些文件find . -regex ".*t\.gif"
。然后我想用basename
strip the filenames,但是为什么会出现以下警告?
$ find . -regex ".*t\.gif" -execdir basename {} \;
find: The relative path `~/program_files/internet/SSH_tunneling/' is included in the PATH environment variable, which is insecure in combination with the -execdir action of find. Please remove that entry from $PATH
$ find . -regex ".*t\.gif" | xargs basename
basename: extra operand ‘./f10_1t.gif’
我该如何继续完成我的任务呢?
可以不使用吗find
?
答案1
是的,这是可能的。一种方法可能如下所示:
cd /den/of/gifs && \
for f in ./*t.gif; do
mv -- "${f%%t.gif}.gif" "$f"
done
这${var%%pattern}
是标准/POSIXsh
语法,用于删除匹配的最长字符串图案从年底开始$var
。
答案2
为了使其更加紧凑和更快,您可以使用parallel
:
parallel mv {} {.}t.gif :::: <(find . -regex '.+[0-9].gif')
after 的表达式::::
提供了 的参数parallel
。然后使用这些参数{}
。表示{.}
不带文件扩展名的参数。因此,在我们的例子中,{}
将是不带 的文件的文件名t
,例如fig8_4.gif
.{.}
那么就会是fig8_4
。
答案3
如果你想继续使用find
和basename
,这应该可行:
find . -name "*.gif" ! -name "*t.gif" -execdir sh -c '
cp -- "$0" "$(basename "$0" .gif)t.gif"' {} \;
从性能和资源角度来看,这不是最佳选择。
答案4
关于您的错误:
find:相对路径‘~/program_files/internet/SSH_tunneling/’包含在PATH环境变量中,与find的-execdir操作结合使用是不安全的。请从 $PATH 中删除该条目
你~/program_files/internet/SSH_tunneling/
在你的$PATH
.那是字面意思~
。确实如此不是意思是你的主目录。相反,这意味着相对路径 ~/program_files/internet/SSH_tunneling/
,即当前目录内的目录SSH_tunneling
内。internet
program_files
~
-execdir
不喜欢相对目录,$PATH
因为它会chdir()
进入要从中执行命令的目录。例如,如果在目录树中下降时,find
找到一个gif
文件,./some-dir
其中也包含一个~
目录,并且有一个./some-dir/~/program_files/internet/SSH_tunneling/basename
,那么它最终可能会执行那 basename
。
您可能有:
PATH="~/program_files/internet/SSH_tunneling/"
在你的~/.bash*
其中应该是:
PATH=~/program_files/internet/SSH_tunneling/
或者
PATH="$HOME/program_files/internet/SSH_tunneling"
$ find . -regex ".*t\.gif" | xargs basename basename: extra operand ‘./f10_1t.gif’
xargs
basename
将使用尽可能多的参数运行。basename
最多需要 2 个参数,第一个参数是路径,第二个参数是模式。所以你的命令没有意义。
另外,xargs
默认情况下,需要在输入上使用空白(空格、制表符以及可能更多,具体取决于您的区域设置和实现find
)和换行符(所有这些都可能出现在文件名中)分隔列表,并对引号进行特殊处理,这不是格式输出经过find
。
find
将输出类似:
./path/to/picture from "The End of the World".gif
这xargs
将被理解为 3 个不同的参数:./path/to/picture
, from
, The End of the World.gif
。find
没有模式以 预期的格式输出xargs
,此处:
./path/to/picture\ from\ \"The\ End\ of\ the\ World\".gif
或者
'./path/to/picture from "The End of the World".gif'
某些xargs
实现确实支持-0
处理 NUL 分隔列表而不是空白/换行符+引号的选项,并且某些find
实现具有-print0
谓词来输出具有该格式的文件名(对于那些不支持的实现,您可以使用-exec printf '%s\0' {} +
它来代替)。
所以像这样:
find . -name "*t.gif" -print0 | xargs -r0 -I {} basename {} t.gif
这对你的总体目标没有多大用处。相反,你可能想要类似的东西:
find . -name '*t.gif' -type f -exec sh -c '
for f do
cp "${f%t.gif}.gif" "$f"
done' sh {} +
或者与zsh
:
autoload zmv # if not already in ~/.zshrc
zmv -C '(**/)(*)t.gif(#qD.)' '$1$2.gif'