Bash问题。在参数列表替换中使用basename命令的Xargs和问题

时间:2011-08-22 07:04:59

标签: bash

我正在使用 bash shell。

您好,脂肪酶 如果有人可以提供某种建议会很高兴,因为谷歌搜索产生了一些答案 但仍然无法使脚本工作。

我是新手使用bash脚本并得到一个脚本来修改,因为它无法复制 处理完文件后,将大量文件从输入目录输入到输出目录。

说明

我们在一个大目录中有一堆pdf。 我们处理一个名为filename.pdf的文件,在处理完一个名为filename.pdf.marker的附加文件后 然后将两个文件filename.pdf.marker和filename.pdf从input / in目录移动到目录output / out。 我们使用大约10-15个文件。

脚本应该执行以下操作:

  1. 选择所有.marker文件名
  2. move.marker文件从input / in目录到目录输出/输出(在单独的行中完成)
  3. 从所选文件名中删除.marker
  4. 将文件filename.pdf移动到输出/输出目录
  5. 旧脚本(不适用于更大数量的文件):

    FILELIST=$(ls ${V04}/*.pdf.marker 2> /dev/null | sort)
    for FILEMARKER in ${FILELIST}; do
        FILENAME=${V04}/$(basename $FILEMARKER .marker)
            mv ${FILENAME} ${VLOGDIR}/.  
            mv ${FILENAME}.marker ${VLOGDIR}/.  
        done  
    

    因此我需要使用xargs命令。

    问题:

    我设法将.marker文件移到另一行。 现在我需要使用此脚本行移动.pdf文件。

    find /input/in -iname "*.marker" -print0 | xargs -0 -r -I {} mv `basename {} .marker`  /output/out
    

    我的问题在于:`basename {} .marker` 为什么不从字符串 filename.pdf.marker 中提取字符串 filename.pdf ,并将其替换为 mv 命令?

    欢迎任何帮助;)

    已更新

    • 更正了脚本应该执行的操作:两种文件类型.pdf 和.pdf.marker应该在我的脚本中移动而不是复制。
    • 添加了对大量文件无效的旧脚本。

5 个答案:

答案 0 :(得分:3)

问题是反引号中的命令在调用xargs之前执行一次。

修复有点困难,尤其是因为你的第2步说'复制',但前面的描述暗示'移动'。我可能会创建一个由xargs调用的简单脚本:

find /input/in -name '*.marker' -print0 | xargs -0 mover.sh

mover.sh的内容可能是:

for mrk_source in "$@"
do
    pdf_source=$(echo "$mrk_source" | sed 's/\.marker$//')
    mrk_target=$(echo "/output/out/$mrk_source" | sed 's%/input/in%%')
    pdf_target=$(echo "/output/out/$pdf_source" | sed 's%/input/in%%')
    mv "$mrk_source" "$mrk_target"
    mv "$pdf_source" "$pdf_target"
done

请注意,此代码保留/input/in下的任何目录结构,但假定/output/out下存在相应的目录(不检查)。可以更改代码以展平任何目录结构,或者根据需要创建目录(为读者练习)。在两个xxx_target赋值行中,文件名操作中有一个小小的手法;我认为它对于相对名称和绝对名称都可以正常工作,但对该部分有点谨慎(换句话说,在使用之前进行测试)。


tripleee评论道:

  

echo和sed调用非常脆弱 - 例如,某些平台上的echo会将文件名中的反斜杠解释为转义序列。幸运的是,您可以使用shell的替换机制代替mv "${mrk_source#.marker}" /output/out。 (当你需要给mv的所有内容都是目标目录时,为什么要计算目标文件名?)

我解释了目标文件名 - 保留子目录,所以/input/in/dir1/abc.pdf转到/output/out/dir1/abc.pdf;如果你想展平目录结构(或者没有目录结构),那么只需指定目的地就足够了。

echo的问题不应该是一个问题,因为回声的原始设计很简单,所有后来的额外......行李只是使得应该完全可靠的东西变得极其不可靠。 也就是说,包含反引号,$(...)等的名称可能存在问题。名称中的反引号或$(...)没有问题。名称中有反斜杠的问题。

$ mkdir -p input/in output/out
$ for name in a b 'c d' 'e  f  g' '$(cat x)' '`cat y`' 'a\\nb'
> do
>    cp /dev/null input/in/"$name.pdf"
>    cp /dev/null "input/in/$name.pdf.marker"
> done
$ ls -lR [io]*
input:
total 0
drwxr-xr-x  16 jleffler  staff  544 Aug 22 00:45 in

input/in:
total 0
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 $(cat x).pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 $(cat x).pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 `cat y`.pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 `cat y`.pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 a.pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 a.pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 a\\nb.pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 a\\nb.pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 b.pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 b.pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 c d.pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 c d.pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 e  f  g.pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 e  f  g.pdf.marker

output:
total 0
drwxr-xr-x  2 jleffler  staff  68 Aug 22 00:45 out

output/out:
$ find input/in -name '*.marker' -print0 | xargs -0 sh mover.sh
mv: rename input/in/a\nb.pdf to ./output/out/a
b.pdf: No such file or directory
$ ls -lR [io]*
input:
total 0
drwxr-xr-x  3 jleffler  staff  102 Aug 22 00:46 in

input/in:
total 0
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 a\\nb.pdf

output:
total 0
drwxr-xr-x  15 jleffler  staff  510 Aug 22 00:46 out

output/out:
total 0
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 $(cat x).pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 $(cat x).pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 `cat y`.pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 `cat y`.pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 a.pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 a.pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 a\nb.pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 b.pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 b.pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 c d.pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 c d.pdf.marker
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 e  f  g.pdf
-rw-r--r--  1 jleffler  staff  0 Aug 22 00:45 e  f  g.pdf.marker
$ 

使用Bash内置插件是明智的;我有时会在20世纪80年代陷入困境,需要提醒一下。

使用反斜杠等的解决方案

for mrk_source in "$@"
do
    pdf_source=${mrk_source%.marker}
    mrk_target=${mrk_source/\/input\/in/\/output\/out}
    pdf_target=${pdf_source/\/input\/in/\/output\/out}
    mv "$mrk_source" "$mrk_target"
    mv "$pdf_source" "$pdf_target"
done

使用相同的输入文件集,此代码可以干净地运行:

答案 1 :(得分:2)

编辑:正如评论中所指出的,如果文件名中有空格,这将无效。在这种情况下,请参阅@Jonathan Leffler的答案(即使没有空格现在,你也应该使用他的版本,以避免在突然出现空格时发生破坏......)。

由于命令在 之前被扩展,因此无法以这种方式使用它。您将给出xargs的命令如下所示:

xargs -0 -r -I {} mv {} /output/out

因为它试图从字符串{}中删除任何路径组件和a .marker后缀。

我想说你想在这种情况下使用循环:

for f in $(find /input/in -iname "*.marker"); do
    mv `basename $f .marker` /output/out
done

答案 2 :(得分:1)

使用GNU Parallel,您应该可以:

ls "$V04"/*.pdf.marker | parallel -q mv {.} {} "$VLOGDIR"

即使$ V04和$ VLOGDIR包含'“space \ t。

,这也会有效

观看介绍视频以了解详情:http://www.youtube.com/watch?v=OpaiGYxkSuQ

答案 3 :(得分:0)

反引号在评估时执行,而不是在xargs运行时执行。也许尝试这样的事情?

find /input/in -iname "*.marker" -print0 |
xargs -r0 -i sh -c 'mv `basename "{}" .marker` /output/out; mv "{}" /output/out'

编辑:shell在这里仍有问题;如果文件名包含双引号,则无法正确解析。使用单独的脚本可能更好:

find /input/in -iname "*.marker" -exec ./myscript {} \;

其中myscript包含简单的移动命令:

#!/bin/sh
mv `basename "$1" .marker` /output/out
mv "$1" /output/out

答案 4 :(得分:0)

旧脚本的问题是,您尝试捕获一个var中的所有条目,这些条目具有大小限制。 如果不能以这种方式对条目进行排序,则可以解决这个问题:

ls -1 "${V04}/*.pdf,.marker | while read FM; 
do 
    mv "${FM}" "${VLOGDIR}/"
    mv "${V04}/$(basename "${FM}" .marker)" "${VLOGDIR}/"
done;