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

时间:2011-09-15 07:29:17

标签: shell unix sh

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

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

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

aaaa
11111-----

但这只是将文件打印到屏幕上,我想将其保存到变量中! 有一个简单的方法吗?

7 个答案:

答案 0 :(得分:870)

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

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

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

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

catbash中调用zsh来篡改文件将被视为Useless Use of Cat

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

请参阅:Bash Hacker's Wiki - Command substitution - Specialities

答案 1 :(得分:81)

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

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

如果你想逐行阅读:

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

答案 2 :(得分:69)

两个重要的陷阱

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

  1. 从命令展开中删除换行符
  2. NUL字符删除
  3. 从命令展开中删除换行符

    这是一个问题:

    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解决方法:在命令扩展中附加一个额外的字符并稍后将其删除:

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

    输出:

    0000000 61 0a 0a
    0000003
    

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

    删除NUL字符

    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扩展名$""文字:

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

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

    陷阱的解决方法

    在变量中存储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。

答案 3 :(得分:2)

使用命令替换Ciro Santilli notes将删除尾随换行符。他们使用添加尾随字符的解决方法很棒,但在使用它很长一段时间之后我决定我需要一个完全没有使用命令替换的解决方案。

My approach现在使用readprintf内置版-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

答案 4 :(得分:2)

这对我有用: www.matakanawine.co.nz/*/ www.matakanawine.co.nz/index.html/ www.matakanawine.co.nz/

答案 5 :(得分:2)

使用bash可以像tis一样使用read

#!/usr/bin/env bash

{ IFS= read -rd '' value <config.txt;} 2>/dev/null

printf '%s' "$value"

注意:

  • 保留最后一个换行符。

  • 通过重定向整个命令块,stderr被静默化为/dev/null,但是如果需要处理读取错误情况,则将保留读取命令的返回状态。

答案 6 :(得分:-2)

您可以通过for循环一次访问1行

#!/bin/bash -eu

#This script prints contents of /etc/passwd line by line

FILENAME='/etc/passwd'
I=0
for LN in $(cat $FILENAME)
do
    echo "Line number $((I++)) -->  $LN"
done

将整个内容复制到File(例如line.sh);执行

chmod +x line.sh
./line.sh