3

I have 3 files: a.txt, b.txt and c.txt. I want to create 3 files: a.test, b.test and c.test containing the simple text "abracadabra". Basicaly, the point is to create the .test files for each .txt file, and containing some text. I am trying to use xargs to do this.

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.

Could someone point out why using the {} placeholder for line-by-line pipe doesn't work the way I expect it to?

1

awk can output text, not need for echo or xargs. Your approach has issues for file names with more than one dot, like foo-1.2.txt.

It would also have issues for filenames with newlines in them or if there are directories whose name ends in .txt.

For once, I'd use a loop here, for instance with zsh:

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

Or POSIXly:

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

The noclobber is to avoid overriding an already existing file. Note that it omits hidden files. If there's no txt file, it will create a *.test file.

1

In this code:

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

xargs will not see the redirection operator > at all: it will be interpreted by your shell instead, creating a file named, literally, {}.test.

One way to do what you ask using xargs is this, which lets sh interpret the redirection operator:

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

But you would probably be better off not using xargs at all, which other answers explain how to do.

  • What if there's a $(rm -rf "$HOME").txt file in the current directory? – Stéphane Chazelas Dec 2 '15 at 17:03
  • Then Bad Things would happen. I added a note to that effect. – dhag Dec 2 '15 at 18:32
  • 1
    Then make it xargs sh -c 'for i do echo abracadrabra > "$i"; done' sh – Stéphane Chazelas Dec 2 '15 at 19:46
  • I tried to answer the explicit question, that asks why the redirect doesn't seem to work. I fully agree that your answer is a much better approach to actually creating .test files. I'm not sure what your point is: do you mean it would be better if I omitted my attempt at fitting a solution within xargs' constraints? – dhag Dec 2 '15 at 20:33
  • 1
    I mean that you shoud not embed the {} in the shell code, pass it as an argument to sh. You could also make it xargs -I{} sh -c 'echo abracadabra > "$1"' sh {} which wouldn't have tha code injection vulnerability but would run one sh per file. – Stéphane Chazelas Dec 2 '15 at 20:40
-2
for l in $(ls *.txt); do echo "abrakadabra" > $l; done
  • 5
    Hello nepsse. Why are you parsing ls instead of just using for l in *.txt? What's $1 intended to be? Generally here we prefer code to be explained rather than just dumped into an answer. – roaima Oct 22 '18 at 18:41
  • 3
    It also doesn't address the question in the Question. – Jeff Schaller Oct 22 '18 at 19:09
  • 2
    This overwrites the original txt files – Michael Mrozek Oct 22 '18 at 22:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.