Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何根据shell中以逗号分隔的内容批量重命名文件?_Shell - Fatal编程技术网

如何根据shell中以逗号分隔的内容批量重命名文件?

如何根据shell中以逗号分隔的内容批量重命名文件?,shell,Shell,我有数百个后缀为.txt的文件。txt文件在带有分隔符的列中包含来自其他列的id[0-9]。我想要的是自动一个接一个地提取id[0-9]作为相应文件的文件名,有什么想法吗 例如:ben.txt,cotains: aa、bb、cc、id2233、kk 还有很多像这样的文件 那么,如何使用shell或其他方法提取id2233以将ben.txt替换为id2233.txt 谢谢。生成脚本以重命名文件 # old.names: generate files with old and new names #

我有数百个后缀为.txt的文件。txt文件在带有分隔符的列中包含来自其他列的id[0-9]。我想要的是自动一个接一个地提取id[0-9]作为相应文件的文件名,有什么想法吗

例如:ben.txt,cotains:

aa、bb、cc、id2233、kk

还有很多像这样的文件

那么,如何使用shell或其他方法提取id2233以将ben.txt替换为id2233.txt


谢谢。

生成脚本以重命名文件

# old.names: generate files with old and new names
# new.names: 
# rename.sh: file with commands to rename

paste old.names new.names | awk '{o = $1; n = $2; print "mv", o, n}' > rename.sh

# if you like how rename.sh looks
sh rename.sh
一个更奇特的版本,允许文件名中有空格

paste old.names new.names | \
    awk -v FS='\t' \
    '{ o = $1
       n = $2
       print "mv --", w(o), w(n)          
     }
     function w(s) { return "'" s "'"} # wrap
    '

我不知道这是否是最好的方法,但是您可以遍历目录中的所有文件,选择id字段,然后发出rename语句。这里有一个方法:

  for oldf in ben*.txt
  do
    newf=""
    echo " "
    echo "Old file: $oldf"
    newf=`grep ",id" $oldf | sed "s/^.*\x2cid\([0-9]*\).*$/id\1.txt/" | head -1`
    echo "New file: $newf"
    if [ ! "$newf" ]; then 
       echo "No valid id found in $oldf.  Please correct before continuing."
       exit 1
    fi
    if [ -f $newf ]; then 
       echo "File exists with id found in $oldf.  Please correct before continuing."
       exit 2
    fi
    echo "rename $oldf $newf"
  done
  echo " "
注意:这将获取带有id字段的第一条记录并使用该字段

这不会假定id字段的任何特定位置,它将使用任何长度编号。但是,它确实假设,id在id号之前

哦,在这个例子中,rename命令被回送到终端,所以它实际上不会做任何事情,只是告诉你它会做什么。你需要移除回音,让它真正做你想做的事情


希望这有帮助

以下是一个谨慎的实现,不会覆盖现有文件;不会将文件移动到当前目录之外;不倾向于;仅使用内置命令,而不是mv命令本身

#!/bin/bash
for f in *.txt; do
  IFS=, read -r _ _ _ id _ <"$f" || continue
  [[ $id = */* ]] && continue ## refuse to move files outside this directory
  [[ $id = .* ]] && continue ## refuse to give files hidden names
  [[ -e $id.txt ]] && continue ## refuse to overwrite files that already exist
  [[ $f = "$id.txt" ]] && continue ## skip if name already matches destination
  mv -- "$f" "$id.txt"
done

你可以通过抛出awk并使用合适的工具来完成这项工作。您的建议类似于用黑线鳕砍掉一棵巨大的加州红木:-查找rename或prename,它们允许您基于Perl正则表达式进行大规模重命名。您的文本描述很难理解。请给出输入和输出文件的示例行。让我重申警告,awk是用于此作业的错误工具。当你使用它的时候,你会遇到很难避免的安全漏洞,如果你的代码是用谨慎编写的shell或直接重命名调用Python、Perl等语言本机实现的,这将是完全有争议的;如果有人在bash或另一个shell中使用$extended quoting语法touch$'$rm-rf$HOME\'$rm-rf$HOME\,您以后就不想在该目录中运行这两个版本的代码了-您在w函数中添加的额外单引号将被名称中的文字所回避。@CharlesDuffy我想您是在开玩笑。按照这个逻辑,mv A B不是一个很好的答案,它回答了一个问题:如何将文件A重命名为B?一点也不开玩笑。告诉某人从firstname='Bobby'所在的学生处选择count*是一种好的做法,与告诉某人可以从firstname='name'所在的学生处使用字符串串联打印select count*安全地形成相同的查询是不同的。其中一个很好,另一个很好。生成shell命令作为字符串echo$oldf$newf是不安全的,原因与我在@slitvinov的回答中给出的相同。也就是说,您可以很容易地修复这个问题:printf'mv%q%q\n'$oldf$newf将生成一个eval-safe命令来执行重命名注意:在UNIX上重命名是1非标准的,2与mv有不同的用法。此外,您应该将日志记录和错误重定向到stderr,而不是将它们与stdout上的输出混合在一起-否则,如果有人将输出重定向到某个文件,他们可能会完全丢失错误日志。查尔斯·达菲说,这很好。在没有任何关于这是OP生成的特定文件集、潜在恶意用户上传的文件还是课堂作业中分发的文件的信息的情况下,我决定将安全性留给OP。不过,始终使用它可能是一种好形式。至于错误消息,我关注的是概念验证,而不是实现。同样,在不了解上下文的情况下,我所能做的就是提供一个它可能如何工作的基本概念——凌晨3点,我没有想到stderr。8^不过,谢谢你的建议!