答案1
该--xform
参数采用任意数量的sed
替代表达式,它们非常强大。在您的情况下,使用匹配所有内容直到最后的模式/
,然后将其替换为任何内容:
tar cvf allfiles.tar --xform='s|.*/||' $(<mylist.txt)
添加--show-transformed-names
以查看新名称。
请注意,此替换适用于所有文件名,而不仅仅是命令行上给出的文件名,因此,例如,如果您有一个文件/a/b/c
并且列表仅指定/a
,则最终文件名只是c
,而不是b/c
。您始终可以更加明确并提供准确的替换列表,例如在您的情况下
--xform='s|^tmp/path2/||;s|^tmp/||;s|^path3/||'
请注意,首字母/
将被 tar 删除(除非您使用-P
),因此上面的表达式会丢失它。此外,必须对目录列表进行排序,以便首先完成最长的匹配,否则tmp/path2/
将不会匹配,因为tmp/
已被删除。但您可以自动创建此列表,例如:
--xform="$(sed <mylist.txt 's|[^/]*$||; s|^/||; s:.*:s|^&||;:' | sort | tr -d '\n')"
答案2
使用 GNU tar
,您可以-C
随时随地使用,并且立即生效。
$ tree
.
├── 1
│ └── aaa
├── 2
│ └── bbb
└── 3
└── ccc
# Caveat: the directory change is always relative to directory tar is using *at
# that time*, so the following doesn't work:
$ tar -cf foo.tar -C 1 aaa -C 2 bbb -C 3 ccc
tar: 2: Cannot open: No such file or directory
tar: Error is not recoverable: exiting now
$ tar -cf foo.tar -C 1 aaa -C ../2 bbb -C ../3 ccc
$ tar tf foo.tar
aaa
bbb
ccc
# You can avoid the special case for the first directory by always specifying
# an absolute path:
$ tar -cf foo.tar -C $(pwd)/1 aaa -C $(pwd)/2 bbb -C $(pwd)/3 ccc
# Now let's create that automatically from your file:
$ cat mylist.txt
/tmp/1/aaa
/tmp/2/bbb
/tmp/3/ccc
$ while read -r line; do printf '-C %s %s ' $(dirname "$line") $(basename "$line") ; done < mylist.txt
-C /tmp/1 aaa -C /tmp/2 bbb -C /tmp/3 ccc
# That looks about right. Let's use it in our tar command:
$ tar -cvf foo.tar $(while read -r line; do printf '-C %s %s ' $(dirname "$line") $(basename "$line") ; done < mylist.txt)
aaa
bbb
ccc