0

This question builds off of a previous question. I do not want to edit the previous question because then I would be introducing a new complexity to a question that already has SO many comments. It would skew the context of the current answers.

The following is the mapping file called mapping.txt

src/a/  tgt/aye/
src/b   tgt/b/
src/c/  tgt/c

The source file structure is as follows

/tmp/testzone/src/a/afile.txt
/tmp/testzone/src/b/bfile.txt
/tmp/testzone/src/c/cfile.txt

First thing we do is create the target directory folder structure based on the mapping.txt file

cut -f 2 mapping.txt | tr '\n' '\0' | xargs -0 mkdir -p

Which creates the target directory folder structure

/tmp/testzone/tgt/aye/
/tmp/testzone/tgt/b/
/tmp/testzone/tgt/c/

Next we run

 xargs --arg-file mapping2.txt cp -a

Which seems to put the source directory contents into the target directory's c directory. This is wrong. It should be using the mapping.txt file to copy from source to target line by line.

/tmp/testzone/tgt/aye/
/tmp/testzone/tgt/b/
/tmp/testzone/tgt/c/a/afile.txt
/tmp/testzone/tgt/c/aye/
/tmp/testzone/tgt/c/b/bfile.txt
/tmp/testzone/tgt/c/c/cfile.txt

What could be causing this issue?

phil o.O
  • 406
  • 2
  • 4
  • 20
  • This is related to a question you've asked in SO not so long ago. May be you should update your other question to show what's not working rather than posting another question. This: https://stackoverflow.com/questions/48305724/bash-script-to-mkdir-on-each-line-of-a-file-that-has-been-split-by-a-delimiter – iamauser Jan 17 '18 at 19:57
  • Possible duplicate of [Bash script to mkdir on each line of a file that has been split by a delimiter?](https://stackoverflow.com/questions/48305724/bash-script-to-mkdir-on-each-line-of-a-file-that-has-been-split-by-a-delimiter) – iamauser Jan 17 '18 at 20:04
  • 2
    eh, it's not really a duplicate. Why would I introduce a new complexity to a question that already has SO many comments? It would skew the context of the answers... – phil o.O Jan 17 '18 at 20:16
  • 1
    Perhaps you are really looking for https://stackoverflow.com/a/29489064/874188 – tripleee Jan 17 '18 at 20:25
  • @tripleee yes. This seems promising. Now I need to figure out how to feed the `mapping.txt` file into the `install SOURCE DEST`. – phil o.O Jan 17 '18 at 20:29
  • 1
    @iamauser I agree with the OP's decision to post a separate question. Updating a question with new requirements after you have received several substantial answers is strongly discouraged on Stack Overflow. – tripleee Jan 17 '18 at 20:40
  • The point is OP is claiming in this question that the suggested answer from the other question isn't working as expected, whereas OP should have said the same in the other question. In general, I don't discourage any sort of questions, but this somehow didn't seem right to me. – iamauser Jan 17 '18 at 20:45
  • Depends on what you expect I guess (-: I thought this was crazy too at first, but it's not an outrageous misunderstanding if you are new to `xargs`, and might actually help others in a similar situation. I see now that my answer basically duplicates an answer to the other question, so you really could go both ways with this. – tripleee Jan 17 '18 at 20:57
  • yes, I am very new to bash. Thank you all for the insight and help. – phil o.O Jan 17 '18 at 21:04
  • 1
    @tripleee see this from the same user: https://stackoverflow.com/questions/48286904/rpmbuild-copying-folders-specified-by-a-mapping-file – iamauser Jan 17 '18 at 21:09

2 Answers2

1

In the absence of options to instruct it otherwise, xargs will put as many lines of possible from the input file as arguments to a single cp invocation. This is what xargs was designed to do.

You can probably find a way to nudge it in the right direction, but this looks like you should simply be doing

while read -r src dst; do
    mkdir -p "${dst%/*}"
    cp -a "$src" "$dst"
done<mapping2.txt

Maybe look at install to further simplify this, as already suggested in a comment.

tripleee
  • 175,061
  • 34
  • 275
  • 318
0

For xargs, each input data item has the same "meaning" -- the tool is designed to perform the same operation on all those items.

Your input data items do not fit that assumption. The mappings.txt file contains a source directory, then a destination directory, then a source directory and so on.

So, you either need to take a different tool/script (as suggested in tripleee's answer), or you need to trim your input data, so it fits the "same items" assumption.

Trimming will require that your input items represent pairs of (source, destination) directories. A 'hack' for doing that would be to tell xargs that only newline characters (and not any whitespace) separates your items. Also, due to the nature of the cp command, each input pair must be handled individually, one at a time. The following should do the trick:

xargs --arg-file mapping.txt --delimiter '\n' --max-args 1 -I PAIR sh -c "cp PAIR"

Putting the input PAIR string in a separate invocation of sh will split the input pairs into two separate words, so they can be used as input for cp.

Alex O
  • 7,746
  • 2
  • 25
  • 38