xargs 和逐行管道

xargs 和逐行管道

我有 3 个文件:a.txtb.txtc.txt.我想创建 3 个文件:a.testb.testc.test包含简单文本abracadabra.

基本上,重点是.test为每个.txt文件创建文件,并用一些文本填充它们。我正在尝试用xargs它来做到这一点。

anlx2626> ls
a.txt  b.txt  c.txt

anlx2626> ls *.txt | awk -F'.txt' '{print $1}' | xargs -I {} echo "abracadabra" > {}.test

anlx2626> ls *.test
ls: No match.

有人能指出为什么使用{}占位符进行逐行管道不能按我期望的方式工作吗?

答案1

在此代码中:

xargs -I {} echo "abracadabra" > {}.test

xargs 根本看不到重定向运算符>:它将由您的 shell 进行解释,创建一个名为 .xargs 的文件 {}.test

使用 xargs 执行您要求的操作的一种方法是这样,它让 sh 解释重定向运算符:

xargs sh -c 'for i do echo abracadrabra > "$i"; done' sh

但你可能最好根本不使用 xargs,其他答案解释了如何做。

答案2

awk可以输出文本,不需要echoxargs。您的方法对于包含多个点的文件名存在问题,例如foo-1.2.txt.

对于包含换行符的文件名或者存在名称以.txt.

这一次,我将在这里使用循环,例如使用 zsh:

(set -o noclobber; for f (*.txt(N)) echo abracadabra > $f:r.test)

或者 POSIXly:

(set -o noclobber
 for f in *.txt; do
   echo abracadabra > "${f%.*}.test"
 done)

noclobber是为了避免覆盖已经存在的文件。请注意,它忽略了隐藏文件。如果没有txt文件,POSIX sh 变体将创建一个*.test文件。

答案3

尽管这个问题已经得到了充分的回答,但我只是添加这个以展示另一种方式:

while IFS= read -r
do
echo abracadabra > "${REPLY}.test"
done < <(find . -maxdepth 1 -name "*.txt" -exec basename -s .txt {} \;)

这里find用于列出文本文件。maxdepth用于阻止 find 递归到子文件夹中。basename -s .txt用于从一开始就删除 txt 扩展名,因为除了列出名称之外,我们根本不需要它。在 while 循环中,我们只需使用不带扩展名的名称,并使用字符串替换来添加.test扩展名,同时回显到文件。请注意,我们使用了 的默认变量while,即$REPLY

答案4

for l in $(ls *.txt); do echo "abrakadabra" > $l; done

相关内容