使用 xargs 将文本复制到文件数组中

使用 xargs 将文本复制到文件数组中

我正在尝试使用 echo、xargs 和 cp 将一个文件的输出复制到多个文件中。我的问题是 xargs 仅打印到数组中的第一个文件,而不是打印到所有 3 个文件的副本。我是否错误地使用了 xargs 或者我的语法不正确。我已经为此工作了几天并且到目前为止没有运气的多个谷歌页面。任何帮助是极大的赞赏!

#!/bin/bash

NF1=/home/user3/mynewfile
U3=/home/user3/
File=(grades mynewfile mynewfile1 mynewfile2)

mkdir -p /home/user3/{CIT/{tests/,grades/},MyStuff/{Tests/,Labs/},NOS/};
echo /etc/hosts.allow > $NF1;
echo $U3/CIT/tests/${File[*]} $U3/CIT/grades/${File[2]} | xargs -n 1 cp $NF1

答案1

正如您怀疑它与语法有关,但我还发现了一些其他问题,并提出了一个版本,它完全放弃了使用xargs而有利于for循环:

#!/bin/bash

U3=/home/user3/
NF1=/home/user3/mynewfile
File=(grades mynewfile mynewfile1 mynewfile2)

mkdir -p /home/user3/{CIT/{tests,grades},MyStuff/{Tests,Labs},NOS};

echo /etc/hosts.allow > $NF1;

for i in "${File[@]}"; do
    cp $NF1 $U3/$i
done

cp $NF1 $U3/CIT/grades/${File[2]}
  • mkdir行被简化以删除不必要的尾部斜杠,mkdir仍然使目录带有或不带有尾部斜杠,因此不需要更多输入

其余变动的原因:

冗余斜线

首先测试几行原代码时:

$ U3=/home/user3/
$ File=(grades mynewfile mynewfile1 mynewfile2)
$ echo $U3/CIT/grades/${File[2]}
/home/user3//CIT/grades/mynewfile1

保存到的路径$U3设置了尾部斜杠,那么该行 $U3/CIT/grades/${File[2]}之后也有一个斜杠,$U3从而导致 bash 将其扩展为/home/user3//CIT/grades/mynewfile1,这是一个问题,因为双斜杠//与 不一样/cp例如可能会抱怨no such file or directory

因此,如果您指的是单斜杠/,建议的方法是首先设置$U3为没有尾随斜杠:

$ U3=/home/user3
$ File=(grades mynewfile mynewfile1 mynewfile2)
$ echo $U3/CIT/tests/${File[2]}
/home/user3/CIT/tests/mynewfile1

所以现在它会产生一条正确的路径,没有多余的斜杠。

不正确的支撑扩展

修正后,下一个错误是:

$ echo $U3/CIT/tests/${File[*]}
/home/user3/CIT/tests/grades mynewfile mynewfile1 mynewfile2

我猜您打算扩展数组中的文件名File,使用/home/user3/CIT/tests通用前缀,有点像用逗号进行大括号扩展:

$ echo tweedle{dum,dee}
tweedledum tweedledee

在这种形式的大括号扩展中

  • 字符串紧邻大括号{之前或之后}或两者,您已经正确完成了
  • 但是使用了word, 逗号另一个词,等等,
  • 但是你放了 a ${File[*]},我还没有看到它以这种方式处理数组内容

$U3相反,要输出由相同的公共起始单词或字符串 ( ) 加上基于数组 ( ) 不同的另一部分组合而成的列表$File,我建议使用for循环:

$ for i in "${File[@]}"; do
> echo $U3/$i
> done

请注意,您不必输入>,bash 会自动提供它来指示行继续。在脚本中你只需:

for i in "${File[@]}"; do
    echo $U3/$i
done

结果总是

/home/user3/grades
/home/user3/mynewfile
/home/user3/mynewfile1
/home/user3/mynewfile2
  • 在 中for i in "${File[@]}"; do,引号 ( "), plus对于让循环正确地将数组中的每个文件名理解为单独的参数@非常重要。for$File

测试

最终目标是将变量引用的单个文件复制到由plus数组 plus$NF1的扩展定义的多个位置$U3$File$U3/CIT/tests/${File[2]}

在本例中,最佳实践是使用 echo 和您打算执行的命令进行测试cp,这样您就可以看到将运行什么,除非您想使用set.首先进行我们的测试:

$ NF1=/home/user3/mynewfile

然后

$ for i in "${File[@]}"; do
> echo cp $NF1 $U3/$i
> done
cp /home/user3/mynewfile /home/user3/grades
cp /home/user3/mynewfile /home/user3/mynewfile
cp /home/user3/mynewfile /home/user3/mynewfile1
cp /home/user3/mynewfile /home/user3/mynewfile2

另外,您似乎想复制到,$U3/CIT/grades/${File[2]}这样我们就不会忘记它,但将其添加为附加行:

$ echo cp $NF1 $U3/CIT/grades/${File[2]}
cp /home/user3/mynewfile /home/user3/CIT/grades/mynewfile1
  • 这一切都cp与将要运行的命令相呼应
  • 它可以被重写以指导参数使用xargs类似于原始代码的方式,但这实际上涉及更多的输入,所以我们避免它

因此,只需删除echo本文示例中的 即可创建最终版本的代码。

答案2

我不知道所写的脚本出了什么问题;正如 don_crissti 指出的那样,用作set -x脚本的第二行是调试的良好开端。我对 xargs 和数组扩展不太了解,无法一眼看出问题所在。

然而,有一个简单的解决方法,它可能是解决这个问题的更好方法无论如何:只需使用tee.它允许您在一个命令中写入多个文件,甚至允许附加文本而不是替换文件内容(如果这是您想要的)。

如果我没读错你的剧本,你想要的应该是这样的:

#!/bin/bash

NF1=/home/user3/mynewfile
U3=/home/user3/
File=(grades mynewfile mynewfile1 mynewfile2)

mkdir -p /home/user3/{CIT/{tests/,grades/},MyStuff/{Tests/,Labs/},NOS/};
cd ${U3}CIT/tests/
echo /etc/hosts.allow | tee ${File[*]} ${U3}CIT/grades/${File[2]} $NF1
cd -

编辑:数组扩展默认使用空格分隔;因此我添加了一个cd文件“mynewfile、mynewfile1、mynewfile2”将在 /home/user3/CIT/tests 中创建,而不是在当前工作目录中。 (毫无疑问,有更干净的方法可以做到这一点。)

相关内容