【问题标题】:How to loop through files in a directory and then read them into a string variable in bash如何遍历目录中的文件,然后将它们读入bash中的字符串变量
【发布时间】:2016-11-07 02:29:40
【问题描述】:

我正在尝试在 bash 中遍历一个包含一些 .txt 文件的目录。我对 bash 的经验很少,但我需要使用它,因为我可以在获得每个文件的内容后运行其他命令。我 想要这样做:

for file in <directory>; do
    read its contents
    do something with the contents
done

我发现如果我硬编码文件名,你可以用一个文件来读取文件:

contents = $(<filename.txt)

并遍历目录中的所有文件,我正在这样做:

for file in dir; do

done

我希望能够遍历所有文件并使用循环中的文件变量读取它们。 但在循环内部,这些都不起作用(我也尝试过这些组合):

for file in dir; do
    contents = $(<$file)
done

for file in dir; do
     contents = $(<"$file")
done

for file in dir; do
     contents = $(<${file##*/})
done

for file in dir; do
     contents = $(<"${file##*/}")
done

for file in dir; do
     contents = $(<$(basename "$file"))
done

for file in dir; do
     filename = $(basename "$file")
     contents = $(<$filename)
done

for file in dir; do
     filename = "${file##*/}"
     contents = $(<$filename)
done

提前感谢您的帮助。

【问题讨论】:

  • for file in dir/*.txt; do echo "Showing $file ......"; contents=$(&lt;"$file"); echo "$contents"; done
  • 我得到命令在 contents=$( 上找不到
  • 我把它放在顶部 #!/bin/bash 否则我将如何确保它的 bash 而不是 sh。文件名保存为 .sh
  • 文件在那里,我事先 cd 到脚本中的那个目录以确保
  • @CostasVrahimis:您的 shell 变量分配在 = 周围都有空格,这是不受支持的。像contents = ...(注意= 周围的空格)之类的东西会让shell 认为你正在执行一个名为contents命令,但它会失败。

标签: linux bash shell unix sh


【解决方案1】:
find <dir_path> -iname '*.txt' -exec cat {} + | your_parser

或者只是

cat /<dir_path>/*.txt | your_parser

【讨论】:

    【解决方案2】:

    更大的问题是你是否真的需要将每个感兴趣的文件的内容读入一个 shell 变量,但为了实现这一点,你尝试的主要问题是你有 空格= 符号在您的变量赋值中,这是不受支持的。

    类似contents = ...(注意= 周围的空格)会使shell 认为您正在执行一个名为contents命令,但会失败。

    因此,解决了该问题并为稳健性添加了变量的双引号,以下应该可以工作:

    dir='.' # sample target dir
    
    for file in "$dir"/*.txt; do
        contents=$(<"$file")  # read contents of file $file
        # ... work with "$contents"
    done
    

    【讨论】:

    • 昨天晚些时候我确实意识到了这一点,但感谢您的帮助
    【解决方案3】:

    您可以使用process substitution &lt;() 执行以下操作

    #!/bin/bash
    
    while IFS= read -r -d '' file
    do
        # Your other actions on the files go here. The `-print0` option in
        # find command helps identify all zip files even with special characters
        # in them.
        # The bash variable "$file" holds the zip file name which you an use in
    
        printf "%s\n%s\n" "Contents of $file:-" "$(<file)"
    
    done < <(find directory/ -name "*.txt" -type f -print0)
    

    【讨论】:

    • 这是一个健壮的解决方案,但它会遍历指定目录的整个 子树,而 OP 自己的尝试只关注*.txt 文件直接 包含在目标目录中。
    • @mklement0:感谢您的敏锐观察,也许find 命令中的-maxdepth 1 选项应该可以解决它?
    • 是的,这样可以解决问题,但说实话,在这种简单的情况下,for file in directory/*.txt; do ... 是更简单、更有效的解决方案。
    【解决方案4】:

    例如,我们假设 file1.txt 包含“texta”,file2.txt 包含“text b”,file3.txt 包含“textc”。 file2.txt 中的文本包含一个空格。

    --

    如果文件是单行文件,或者您不需要单独处理每一行,那么您的 for 循环就非常完整了。

    for file in dir/*; do
        contents="$contents $(<"$file")"
    done
    

    但是,这会产生一行,每个文件条目由空格分隔。根据以后如何使用变量,这可能会导致问题。文件中的空格和每个条目周围的空格是不分青红皂白的

    #Value of $contents:
    texta text b textc
    

    您可以改为使用将每个文件文本拆分为新行;

    contents="$contents\n$(<"$file")"
    
    #Value of $contents:
    texta
    text b
    textc
    

    但如果您的文本文件本身包含多行,也会发生同样的问题。

    您还可以将每个文件的文本拆分为数组中的单独索引。

    contents+=("$(<"$file")")
    

    使用数组,每个条目都可以用 ${contents[$i]} 引用,其中 $i 是索引号。

    #Value of ${contents[0]}
    texta
    #Value of ${contents[1]}
    text b
    #Value of ${contents[2]}
    textc
    #Value of $(contents[*]} is all indexes. Listed values are automatically separated by a space.
    texta text b textc
    

    当然也可以不分离,

    contents="$contents$(<"$file")"
    
    #Value of $contents:
    textatext btextc
    

    --

    话虽如此,如果您需要逐行拆分文件,每个文件的每一行都分开,您可以使用嵌入的 while 循环来做到这一点。

    for file in dir; do
        while read line; do
            contents="$contents $(<"$line")"
        done <$file
    done
    

    这会在 for 循环中找到的每个文件运行一次 while 循环。同样,变量赋值行可以根据需要替换为任何其他方法。

    【讨论】:

    • 我不认为 OP 希望将 多个 文件的内容累积到一个变量中。
    猜你喜欢
    • 1970-01-01
    • 2014-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多