views:

78

answers:

3

I have the following directory structure:

+-archive
  +-a
    +-data.txt
  +-b
    +-data.txt 
+-incoming
  +-a
    +-data.txt
  +-c
    +-data.txt

How do I do the equivalent of mv incoming/* archive/ but have the contents of the files in incoming appended to those in archive rather than overwrite them?

+2  A: 
# move to incoming/ so that we don't
# need to strip a path prefix
cd incoming

# create directories that are missing in archive
for d in `find . -type d`; do
  if [ ! -d "../archive/$d" ]; then
    mkdir -p "../archive/$d"
  fi
done

# concatenate all files to already existing
# ones (or automatically create them)
for f in `find . -type f`; do
  cat "$f" >> "../archive/$f"
done

This should find any file in incoming and concatenate it to an existing file in archive.

The important part is to be inside incoming, because else we'd had to strip the path prefix (which is possible, but in the above case unnecessary). In the above case, a value of $f typically looks like ./a/data.txt, and hence the redirection goes to ../archive/./a/data.txt.

Boldewyn
Thanks for the answer (and the welcome). It does just what I was looking for.
A: 

Here's a version with proper quoting:

#!/bin/sh
if [ -z "$1" ]; then
    # acting as parent script
    find incoming -type f -exec "$0" {} \;
else
    # acting as child script
    for in_file; do
        if [ -f "$in_file" ]; then
            destfile="${in_file/incoming/archive}"
            test -d "$(dirname "$destfile")" || mkdir -p "$_"
            cat "$in_file" >> "$destfile" &&
            rm -f "$in_file"
        fi
    done
fi
amphetamachine
The problem is, that `basename` is too little. Inside incoming and archive, there seems to be a significant directory structure.
Boldewyn
@Boldewyn - Acknowledged and fixed. Now it uses Bash's regex replacement.
amphetamachine
You're not setting `in_file` anywhere and it's missing a dollar sign in the for statement.
Dennis Williamson
@Dennis - It's proper syntax. `for in_file; do` is just shorthand for `for in_file in "$@"; do` which will cycle through all arguments to the script, setting the variable `$in_file` to the current argument. Using a dollar sign in the `for` statement is improper syntax... Perhaps it is time to read up on BASH syntax.
amphetamachine
You're right. I had forgotten about that feature. I just find it more readable to refer to `"$@"` explicitly. Perhaps readability is a valid goal.
Dennis Williamson
A: 

run it on the current directory.

find ./incoming  -type f | while read -r FILE
do
  dest=${FILE/incoming/archive}
  cat "$FILE" >> "$dest"
done

the one in incoming/c would not be appended though

ghostdog74