如何引用xargs中{}所指代对象/字符串的基名?批量处理.fam文件时的临时文件重命名方法
解决xargs中{}的引用与批量处理.fam文件的问题
1. 正确在xargs中访问{}并避免临时文件冲突
你原来的命令存在一个核心问题:所有通过xargs处理的文件会共用同一个tmp文件,这会导致文件内容被覆盖,最终只有最后一个文件的处理结果能保留。要让每个文件拥有独立的处理流程,需要把整个命令逻辑放到子shell中执行,确保每一次{}的替换都在独立上下文里完成:
xargs -I {} sh -c 'COMMAND HERE "$1" > "$1.tmp" && mv "$1.tmp" "$1"' _ {}
关键要点:
- 用
sh -c包裹整个命令,让每个{}对应一次独立的shell执行 $1代表传入的文件名(即原来的{}),用双引号包裹能避免文件名含空格、特殊字符的问题- 临时文件命名为
$1.tmp,确保每个文件的临时文件唯一,不会互相覆盖
2. 批量处理.fam文件的正确命令
针对你的.fam文件修改需求(将第6列的1改成0,2改成1),不需要两次awk调用,一次awk就能完成所有替换。结合xargs的正确用法,批量处理的命令应该是:
ls *.fam | xargs -I {} sh -c 'awk '\''{gsub("1","0",$6); gsub("2","1",$6)}1'\'' "$1" > "$1.tmp" && mv "$1.tmp" "$1"' _ {}
如果要避免ls命令在处理特殊文件名(比如含换行)时的潜在问题,更稳妥的方式是用find替代:
find . -maxdepth 1 -type f -name "*.fam" | xargs -I {} sh -c 'awk '\''{gsub("1","0",$6); gsub("2","1",$6)}1'\'' "$1" > "$1.tmp" && mv "$1.tmp" "$1"' _ {}
补充说明:
- 合并两次awk调用为一次,提升处理效率:
awk '{gsub("1","0",$6); gsub("2","1",$6)}1',其中1是awk的惯用写法,用于打印所有处理后的行 - 用
sh -c确保每个文件的处理流程独立,彻底避免临时文件冲突 - 双引号包裹
$1,兼容带空格的特殊文件名
3. 引用xargs中{}的基名
如果需要获取{}对应的文件名(不含路径),可以用basename命令实现。比如你想把处理后的文件放到指定目录,只保留原文件的基名:
find /path/to/fams -name "*.fam" | xargs -I {} sh -c ' base=$(basename "$1") awk '\''{gsub("1","0",$6); gsub("2","1",$6)}1'\'' "$1" > "/path/to/output/$base" ' _ {}
这里base=$(basename "$1")就提取了{}的基名(例如/a/b/file.fam会被处理成file.fam)。如果需要去掉文件后缀(比如得到file),可以用basename "$1" .fam实现。
内容的提问来源于stack exchange,提问作者Sky Scraper
相关产品推荐
相关产品推荐

