【问题标题】:Use the folder name as a column in a text file将文件夹名称用作文本文件中的列
【发布时间】:2012-03-13 07:39:55
【问题描述】:

懒惰的我正在考虑在一些文本文件中添加一列。

文本文件位于目录中,我想将目录名称添加到文本文件中。

喜欢文件夹the_peasant中的文本文件text.txt

has a wart    
was dressed up like a witch     
has a false nose

会变成:

the_peasant has a wart    
the_peasant was dressed up like a witch    
the_peasant has a false nose

然后我在其他名为“the_king”等的文件夹中有类似的文本文件。

我认为这是 find 命令、bash 脚本和 sed 的组合,但我看不透。有什么想法吗?

【问题讨论】:

  • 懒惰的我建议您发布一些代码以表明您至少在这方面做了一些工作。

标签: python perl bash sed awk


【解决方案1】:

我愿意。

  • 获取文件路径,例如 fpath = "example.txt"
  • 使用以下命令查找该文件的目录
  • 读取文件并写入新文件,将 dir_name 附加到写入前刚读取的行。

访问目录可以使用

import os
fpath = "example.txt"
dir_name = os.path.dirname(fpath)

【讨论】:

    【解决方案2】:

    您是否在适当的文件夹中运行脚本?然后你可以使用 os 模块找到当前文件夹。假设您只想取目录树的末尾,您可以使用 os.path,例如:

    import os, os.path
    
    curDirectory = os.getcwd()
    baseDir = os.path.basename()
    
    inFile = open("filename.txt").xreadlines()
    outFile = open("filename.out", "w")
    
    for line in inFile:
        outFile.write("%s %s" % (baseDir, line))
    outFile.close()
    

    【讨论】:

      【解决方案3】:

      为此的简单python脚本(应该在任何文件夹中工作,只要你将完整路径传递给目标文件,显然):

      #!/usr/bin/python
      if __name__ == '__main__':
          import sys
          import os
      
          # Get full filepath and directory name
          filename = os.path.abspath(sys.argv[1])
          dirname = os.path.split(os.path.dirname(filename))[1]
      
          # Read current file contents
          my_file = open(filename, 'r')
          lines = my_file.readlines()
          my_file.close()
      
          # Rewrite lines, adding folder name to the start
          output_lines = [dirname + ' ' + line for line in lines]
          my_file = open(filename, 'w')
          my_file.write('\n'.join(output_lines))
          my_file.close()
      

      【讨论】:

      • 假设您的文件足够小,可以完全保存在内存中
      【解决方案4】:

      这是我想出的:

      find /path/to/dir -type f | sed -r 'p;s:.*/(.*)/.*:\1:' | xargs -n 2 sh -c 'sed -i "s/^/$1 /" $0'
      

      这是一个如何构造命令的示例,假设存在以下文件:

      /home/the_peasant/a.txt
      /home/the_peasant/b.txt
      /home/the_peasant/farmer/c.txt
      

      第一个 find /home/the_peasant -type f 将完全按照上述方式输出这些文件。

      接下来,sed 命令会输出一个文件名,后跟目录名,如下所示:

      /home/the_peasant/a.txt
      the_peasant
      /home/the_peasant/b.txt
      the_peasant
      /home/the_peasant/farmer/c.txt
      farmer
      

      xargs 将每两行分组并将它们传递给 sh 命令,因此您最终会得到以下三个命令:

      $ sh -c 'sed -i "s/^/$1 /" $0' /home/the_peasant/a.txt the_peasant
      $ sh -c 'sed -i "s/^/$1 /" $0' /home/the_peasant/b.txt the_peasant
      $ sh -c 'sed -i "s/^/$1 /" $0' /home/the_peasant/farmer/c.txt farmer
      

      最后,这将导致以下 sed 命令将文件夹名称添加到每行的开头:

      $ sed -i "s/^/the_peasant /" /home/the_peasant/a.txt
      $ sed -i "s/^/the_peasant /" /home/the_peasant/b.txt
      $ sed -i "s/^/farmer /" /home/the_peasant/farmer/c.txt
      

      【讨论】:

        【解决方案5】:

        编辑:注意到有些地方不正确。 我删除了 dir 循环——它现在递归地行走。 很抱歉混淆了。

        使用 os.walk

        import os.path
        directory = os.path.curdir
        pattern = ".py";
        for (path,dirs,files) in os.walk(directory):
            for file in files:
                if not file.endswith(pattern):
                    continue
                filename = os.path.join(path,file)
                #print "file: ",filename
                #continue
                with open(filename,"r") as f:
                    for line in f.readlines():
                        print "{0} {1}".format(filename,line)
                    f.close()
        

        输出:

        list1.py   # LAB(replace solution)
        list1.py   # return
        list1.py   # LAB(end solution)
        

        【讨论】:

          【解决方案6】:

          使用 find 和 perl 的强制单行

          find . -maxdepth 1 -mindepth 1 -type d | perl -MFile::Basename -ne 'chomp; my $dir = basename($_); for my $file (glob "$dir/*") { print qq{sed -i "s/^/$dir /" $file\n} }' | tee rename_commands.sh
          
          sh rename_commands.sh
          

          假设 perl 和 sed 在你的 $PATH 中。生成一个 sed 命令文件以进行实际更改,以便您查看要执行的操作。

          在我的测试中,该命令文件如下所示:

          sed -i "s/^/foo /" foo/text1
          sed -i "s/^/foo /" foo/text2
          sed -i "s/^/bar /" bar/belvedere
          sed -i "s/^/bar /" bar/robin
          

          【讨论】:

          • 你会因为那个单线而获得 +1,因为......嗯,是的
          • 是的,我认为 one-liners 和 perl 的代表性不足,所以我决定一石二鸟。
          【解决方案7】:

          目录树:

          % tree .
          .
          ├── the_king
          │   └── text.txt
          ├── the_knight
          │   └── text.txt
          ├── the_peasant
          │   └── text.txt
          └── wart.py
          3 directories, 4 files
          

          之前的目录和内容:

          % find . -name 'text.txt' -print -exec cat {} \;       
          ./the_king/text.txt
          has a wart    
          was dressed up like a witch     
          has a false nose
          ./the_knight/text.txt
          has a wart    
          was dressed up like a witch     
          has a false nose
          ./the_peasant/text.txt
          has a wart    
          was dressed up like a witch     
          has a false nose
          

          代码(wart.py):

          #!/usr/bin/env python
          
          import os
          
          text_file = 'text.txt'
          cwd = os.path.curdir # '.'
          
          # Walk thru each directory starting at '.' and if the directory contains
          # 'text.txt', print each line of the file prefixed by the name containing
          # directory.
          for root, dirs, files in os.walk(cwd):
              if text_file in files: # We only care IF the file is in this directory.
                  print 'Found %s!' % root
                  filepath = os.path.join(root, text_file) # './the_peasant/text.txt'
                  root_base = os.path.basename(root)       # './the_peasant' => 'the_peasant'
                  output = ''
                  with open(filepath, 'r') as reader:      # Open file for read/write
                      for line in reader:                  # Iterate the lines of the file
                          new_line = "%s %s" % (root_base, line)
                          print new_line,
                          output += new_line               # Append to the output
          
                  with open(filepath, 'w') as writer:
                      writer.write(output)                 # Write to the file
          
                  print
          

          哪些输出:

          Found ./the_king!
          the_king has a wart    
          the_king was dressed up like a witch     
          the_king has a false nose
          
          Found ./the_knight!
          the_knight has a wart    
          the_knight was dressed up like a witch     
          the_knight has a false nose
          
          Found ./the_peasant!
          the_peasant has a wart    
          the_peasant was dressed up like a witch     
          the_peasant has a false nose
          

          之后的目录和内容:

          % find . -name 'text.txt' -print -exec cat {} \;
          ./the_king/text.txt
          the_king has a wart    
          the_king was dressed up like a witch     
          the_king has a false nose
          ./the_knight/text.txt
          the_knight has a wart    
          the_knight was dressed up like a witch     
          the_knight has a false nose
          ./the_peasant/text.txt
          the_peasant has a wart    
          the_peasant was dressed up like a witch     
          the_peasant has a false nose
          

          这很有趣!感谢您的挑战!

          【讨论】:

          • 谢谢,我用它做了一些小的改动。我希望从 bash 脚本或 per/sed/awk 一个班轮中学习,但这太诱人了。
          • 太棒了我很高兴你发现它很有用! :) 单行脚本有它们的位置,但脚本是永恒的。
          【解决方案8】:

          这是 bash 和 awk 中的一个单行代码:

          find . -type f -print0 |
          while read -r -d "" path; do
            mv "$path" "$path.bak"
            awk -v dir="$(basename "$(dirname "$path")")" '{print dir, $0}' "$path.bak" > "$path"
          done
          

          【讨论】:

            【解决方案9】:

            这可能对你有用:

            find . -name text.txt | sed 's|.*/\(.*\)/.*|sed -i "s@^@\1 @" & |' | sh
            

            或者如果你有 GNU sed:

            find . -name text.txt | sed 's|.*/\(.*\)/.*|sed -i "s@^@\1 @" & |e' 
            

            【讨论】:

            • 现在这是一个非常甜蜜的单行字。
            猜你喜欢
            • 1970-01-01
            • 2021-05-15
            • 1970-01-01
            • 2016-09-13
            • 2011-02-09
            • 1970-01-01
            • 1970-01-01
            • 2020-06-29
            • 1970-01-01
            相关资源
            最近更新 更多