it-swarm.cn

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

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

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

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

aaaa
11111-----

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

391
kaka

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

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

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

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

catbash中调用zsh到Slurp文件将被视为 无用的Cat

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

请参阅: Bash Hacker的Wiki - 命令替换 - 专业

859
Alan Gutierrez

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

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

如果你想逐行阅读:

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

两个重要的陷阱

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

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

从命令扩展中删除换行符

这是一个问题:

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 encode。见下文。

删除NUL字符

没有合理的Bash方式将NUL字符存储在变量中

这会影响扩展和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 package)...除了写入另一个文件外,我没有看到bash进程<()替换扩展的POSIX 7替代方案...

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

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

2
angelo.mastro

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

我的方法 现在使用readprintf builtin的 -v标志 以便将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
2
dimo414