我想读取一个文件并将其保存在变量中,但我需要保留变量而不是打印出文件。 我怎样才能做到这一点?我写过这个剧本,但它不是我需要的:
#!/bin/sh
while read LINE
do
echo $LINE
done <$1
echo 11111-----------
echo $LINE
在我的脚本中,我可以将文件名作为参数,因此,如果文件包含“aaaa”,例如,它会打印出来:
aaaa
11111-----
但这只是将文件打印到屏幕上,我想将其保存到变量中! 有一个简单的方法吗?
答案 0 :(得分:870)
在您使用的跨平台,最低公分母sh
:
#!/bin/sh
value=`cat config.txt`
echo "$value"
在bash
或zsh
中,将整个文件读入变量而不调用cat
:
#!/bin/bash
value=$(<config.txt)
echo "$value"
在cat
或bash
中调用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)
两个重要的陷阱
到目前为止被其他答案忽略了:
从命令展开中删除换行符
这是一个问题:
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现在使用read
和printf
内置版-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