我正在尝试使用 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 中创建,而不是在当前工作目录中。 (毫无疑问,有更干净的方法可以做到这一点。)