O comportamento que você está procurando é um caso especial :
cp -R [-H|-L|-P] [-fip] source_file... target[This] form is denoted by two or more operands where the -R option is specified. The cp utility shall copy each file in the file hierarchy rooted in each source_file to a destination path named as follows:
- If target exists and names an existing directory, the name of the corresponding destination path for each file in the file hierarchy shall be the concatenation of target, a single
<slash>character if target did not end in a<slash>, and the pathname of the file relative to the directory containing source_file.- If target does not exist and two operands are specified, the name of the corresponding destination path for source_file shall be target; the name of the corresponding destination path for all other files in the file hierarchy shall be the concatenation of target, a
<slash>character, and the pathname of the file relative to source_file.It shall be an error if target does not exist and more than two operands are specified ...
Portanto, eu diria que não é possível fazer com que cp faça o que você quer.
Como seu comportamento esperado é " cp -r dir1 dir2 (quando dir2 já existir) removerá o dir2 (e qualquer conteúdo) existente e o substituirá por dir1 ":
rm -rf dir2 && cp -r dir1 dir2
Você nem precisa verificar se dir2 existe.
A solução rsync estaria adicionando um / à fonte para que não copiasse dir1 em dir2 , mas copiasse o conteúdo de dir1 para dir2 (ainda será manter arquivos existentes em dir2 ):
$ tree dir*
dir1
└── test.txt
dir2
└── test2.txt
0 directories, 2 file
$ rsync -a dir1/ dir2
$ tree dir*
dir1
└── test.txt
dir2
└── test.txt
└── test2.txt
0 directories, 3 files
$ rm -r dir2
$ rsync -a dir1/ dir2
$ tree dir*
dir1
└── test.txt
dir2
└── test.txt
0 directories, 2 files