简体   繁体   中英

Xargs append string to files

I have multiple text files in a directory. At the end I want to append a string.

Eg. List of text files in directory.

  • a.txt
  • b.txt
  • c.txt

Command to get their path:

find -name "*txt"

Then I tried to send

'echo "example text" > <filename>

So I tried running the following:

find -name "*txt" | xargs echo "example_text" >>

This command fails.

All I want to is append some text to the files every now and then and since the names of the files keep changing I wanted to use xargs

xargs isn't really appropriate here. Maybe a loop over filenames like

for file in *.txt; do
    echo "example_text" >>"$file"
done

Because >> is a shell directive, if you want it honored via xargs, you need to have xargs start a shell. As Shawn's answer demonstrates, in many cases a shell glob is enough and you don't need find at all; but if you do want to use find , it can be used correctly either with or without xargs.


If you insist on using xargs , even though it isn't the best tool for the job...

find . -name "*.txt" -print0 | xargs -0 sh -c '
  for arg in "$@"; do echo "example_text" >>"$arg"; done
' _

Taking xargs out, and just using find (with -exec... {} + to get the same performance benefits xargs would otherwise offer):

find . -name "*.txt" -exec sh -c '
  for arg in "$@"; do echo "example_text" >>"$arg"; done
' _ {} +

(in both of the above, the _ substitutes for $0 , so later arguments become $1 and later, and are thus iterated over when expanding "$@" ).

Append a string to multiple files, using tee -a !

Un*x command tee are built for this kind of operation and is a lot quicker!!

find . -type f -name '*.txt' -exec tee -a <<<'Foo bar baz' {} >/dev/null +

But herestring will work only if tee are executed only once! (thanks to Charles Duffy's comment )!

See pure using globstar further.

And if really you want use xargs

find . -type f -name '*.txt' -print0 |
    xargs -0 sh -c 'echo "Foo bar baz"|tee -a "$@" >/dev/null ' _

But are find really required?

If all files are under same directory:

tee -a <<<'Foo bar baz' >/dev/null *.txt

Else, under [ŧag:bash], using globstar ( shopt -s globstar ):

tee -a <<<'Foo bar baz' >/dev/null **/*.txt

As many pointed out, xargs is not appropriate, so you could just simply use find and pipe to read in a loop to accomplish what you want easily as shown below.

find . -name "*.txt" | while read fname; do echo "example_text">>$fname; done

From the point of view of bash , there are three parts in your command:

  • Before the pipe character ( find -name "*txt" )
  • Between the pipe and the redirection ( xargs echo "example_text" )
  • After the redirection ( )

bash tries to open the output file provided after the redirection but, as you didn't provided anything, bash cannot open "nothing" and fails.

To solve your issue, you need to give xargs a way to add the line you need to the file (without asking bash to redirect the output of xargs ). A way that should work could be by starting a subshell that performs that operation:

find -name "*txt" | xargs -I{} bash -c 'echo "example_text" >> {}'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM