首页 文章

如何将文件读入shell中的变量?

提问于
浏览
351

我想读取一个文件并将其保存在变量中,但我需要保留变量而不是打印出文件 . 我怎样才能做到这一点?我写过这个脚本,但它不是我需要的:

#!/bin/sh
while read LINE  
do  
  echo $LINE  
done <$1  
echo 11111-----------  
echo $LINE

在我的脚本中,我可以将文件名作为参数,因此,如果文件包含“aaaa”,例如,它会打印出来:

aaaa
11111-----

但这只是将文件打印到屏幕上,我想将其保存到变量中!是否有捷径可寻?

5 回答

  • 71

    这对我有用: v=$(cat <file_path>) echo $v

  • 62

    如果要将整个文件读入变量:

    #!/bin/bash
    value=`cat sources.xml`
    echo $value
    

    如果你想逐行阅读:

    while read line; do    
        echo $line    
    done < file.txt
    
  • 1

    Two important pitfalls

    到目前为止被其他答案忽略了:

    • 从命令扩展中删除换行符

    • NUL字符删除

    Trailing newline removal from command expansion

    这是一个问题:

    value="$(cat config.txt)"
    

    类型解决方案,但不适用于基于 read 的解决方案 .

    命令扩展删除尾随换行符:

    S="$(printf "a\n")"
    printf "$S" | od -tx1
    

    输出:

    0000000 61
    0000001
    

    这打破了从文件中读取的天真方法:

    FILE="$(mktemp)"
    printf "a\n\n" > "$FILE"
    S="$(<"$FILE")"
    printf "$S" | od -tx1
    rm "$FILE"
    

    POSIX解决方法:在命令扩展中附加一个额外的char并稍后将其删除:

    S="$(cat $FILE; printf a)"
    S="${S%a}"
    printf "$S" | od -tx1
    

    输出:

    0000000 61 0a 0a
    0000003
    

    几乎POSIX解决方法:ASCII编码 . 见下文 .

    NUL character removal

    There is no sane Bash way to store NUL characters in variables .

    这会影响扩展和 read 解决方案,我不知道有什么好的解决方法 .

    例:

    printf "a\0b" | od -tx1
    S="$(printf "a\0b")"
    printf "$S" | od -tx1
    

    输出:

    0000000 61 00 62
    0000003
    
    0000000 61 62
    0000002
    

    哈,我们的NUL走了!

    解决方法:

    • ASCII编码 . 见下文 .

    • 使用bash扩展名 $"" literals:

    S=$"a\0b"
    printf "$S" | od -tx1
    

    仅适用于文字,因此对于从文件中读取无用 .

    Workaround for the pitfalls

    将uuencode base64编码版本的文件存储在变量中,并在每次使用前解码:

    FILE="$(mktemp)"
    printf "a\0\n" > "$FILE"
    S="$(uuencode -m "$FILE" /dev/stdout)"
    uudecode -o /dev/stdout <(printf "$S") | od -tx1
    rm "$FILE"
    

    输出:

    0000000 61 00 0a
    0000003
    

    uuencode和udecode是POSIX 7但默认情况下不在Ubuntu 12.04中( sharutils 包)...除了写入另一个文件外,我没有看到用于bash进程 <() 替换扩展的POSIX 7替代方案...

    当然,这很慢且不方便,所以我猜真正的答案是:如果输入文件可能包含NUL字符,请不要使用Bash .

  • 775

    在跨平台,最低公分母 sh 您使用:

    #!/bin/sh
    value=`cat config.txt`
    echo "$value"
    

    bashzsh 中,将整个文件读入变量而不调用 cat

    #!/bin/bash
    value=$(<config.txt)
    echo "$value"
    

    bashzsh 中调用 cat 来篡改文件将被视为Useless Use of Cat .

    请注意,没有必要引用命令替换来保留换行符 .

    见:Bash Hacker's Wiki - Command substitution - Specialities .

  • 1

    由于Ciro Santilli notes使用命令替换将丢弃尾随换行符 . 他们添加尾随字符的解决方法很棒,但在使用它很长一段时间之后我决定我需要一个根本不使用命令替换的解决方案 .

    My approach现在使用 readprintf builtin的-v flag,以便将stdin的内容直接读入变量 .

    # Reads stdin into a variable, accounting for trailing newlines. Avoids needing a subshell or
    # command substitution.
    read_input() {
      # Use unusual variable names to avoid colliding with a variable name
      # the user might pass in (notably "contents")
      : "${1:?Must provide a variable to read into}"
      if [[ "$1" == '_line' || "$1" == '_contents' ]]; then
        echo "Cannot store contents to $1, use a different name." >&2
        return 1
      fi
    
      local _line _contents
       while read -r _line; do
         _contents="${_contents}${_line}"$'\n'
       done
       _contents="${_contents}${_line}" # capture any content after the last newline
       printf -v "$1" '%s' "$_contents"
    }
    

    这支持带有或不带尾随换行符的输入 .

    用法示例:

    $ read_input file_contents < /tmp/file
    # $file_contents now contains the contents of /tmp/file
    

相关问题