我想读取一个文件并将其保存在变量中,但我需要保留变量而不是打印出文件.我怎样才能做到这一点?我写过这个剧本,但它不是我需要的:
#!/bin/sh
while read LINE
do
echo $LINE
done <$1
echo 11111-----------
echo $LINE
Run Code Online (Sandbox Code Playgroud)
在我的脚本中,我可以将文件名作为参数,因此,如果文件包含"aaaa",例如,它会打印出来:
aaaa
11111-----
Run Code Online (Sandbox Code Playgroud)
但这只是将文件打印到屏幕上,我想将其保存到变量中!是否有捷径可寻?
Ala*_*rez 940
在跨平台,最低通用分母中,sh
您使用:
#!/bin/sh
value=`cat config.txt`
echo "$value"
Run Code Online (Sandbox Code Playgroud)
在bash
或中zsh
,将整个文件读入变量而不调用cat
:
#!/bin/bash
value=$(<config.txt)
echo "$value"
Run Code Online (Sandbox Code Playgroud)
调用cat
中bash
或zsh
以啜文件会被认为是猫无用的使用.
请注意,没有必要引用命令替换来保留换行符.
请参阅:Bash Hacker的Wiki - 命令替换 - 专业.
bra*_*ain 85
如果要将整个文件读入变量:
#!/bin/bash
value=`cat sources.xml`
echo $value
Run Code Online (Sandbox Code Playgroud)
如果你想逐行阅读:
while read line; do
echo $line
done < file.txt
Run Code Online (Sandbox Code Playgroud)
Cir*_*四事件 72
两个重要的陷阱
到目前为止被其他答案忽略了:
从命令扩展中删除换行符
这是一个问题:
value="$(cat config.txt)"
Run Code Online (Sandbox Code Playgroud)
类型解决方案,但不适用于read
基础解决方案
命令扩展删除尾随换行符:
S="$(printf "a\n")"
printf "$S" | od -tx1
Run Code Online (Sandbox Code Playgroud)
输出:
0000000 61
0000001
Run Code Online (Sandbox Code Playgroud)
这打破了从文件中读取的天真方法:
FILE="$(mktemp)"
printf "a\n\n" > "$FILE"
S="$(<"$FILE")"
printf "$S" | od -tx1
rm "$FILE"
Run Code Online (Sandbox Code Playgroud)
POSIX解决方法:在命令扩展中附加一个额外的char并稍后将其删除:
S="$(cat $FILE; printf a)"
S="${S%a}"
printf "$S" | od -tx1
Run Code Online (Sandbox Code Playgroud)
输出:
0000000 61 0a 0a
0000003
Run Code Online (Sandbox Code Playgroud)
几乎POSIX解决方法:ASCII编码.见下文.
NUL字符删除
这会影响扩展和read
解决方案,我不知道有什么好的解决方法.
例:
printf "a\0b" | od -tx1
S="$(printf "a\0b")"
printf "$S" | od -tx1
Run Code Online (Sandbox Code Playgroud)
输出:
0000000 61 00 62
0000003
0000000 61 62
0000002
Run Code Online (Sandbox Code Playgroud)
哈,我们的NUL走了!
解决方法:
ASCII编码.见下文.
使用bash扩展$""
文字:
S=$"a\0b"
printf "$S" | od -tx1
Run Code Online (Sandbox Code Playgroud)
仅适用于文字,因此对于从文件中读取无用.
陷阱的解决方法
将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"
Run Code Online (Sandbox Code Playgroud)
输出:
0000000 61 00 0a
0000003
Run Code Online (Sandbox Code Playgroud)
uuencode和udecode是POSIX 7但默认情况下不在Ubuntu 12.04中(sharutils
包)... <()
除了写入另一个文件外,我没有看到bash进程替换扩展的POSIX 7替代方案...
当然,这很慢且不方便,所以我猜真正的答案是:如果输入文件可能包含NUL字符,请不要使用Bash.
正如Ciro Santilli 所指出的,使用命令替换会删除尾随换行符。他们添加尾随字符的解决方法很棒,但在使用了相当长一段时间后,我决定需要一个根本不使用命令替换的解决方案。
我的方法read
现在与printf
内置-v
标志一起使用,以便将 stdin 的内容直接读取到变量中。
# Reads stdin into a variable, accounting for trailing newlines. Avoids
# needing a subshell or command substitution.
# Note that NUL bytes are still unsupported, as Bash variables don't allow NULs.
# See https://stackoverflow.com/a/22607352/113632
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 IFS='' read -r _line; do
_contents+=("$_line"$'\n')
done
# include $_line once more to capture any content after the last newline
printf -v "$1" '%s' "${_contents[@]}" "$_line"
}
Run Code Online (Sandbox Code Playgroud)
这支持带或不带尾随换行符的输入。
用法示例:
$ read_input file_contents < /tmp/file
# $file_contents now contains the contents of /tmp/file
Run Code Online (Sandbox Code Playgroud)
使用 bash 你可以这样使用read
:
#!/usr/bin/env bash
{ IFS= read -rd '' value <config.txt;} 2>/dev/null
printf '%s' "$value"
Run Code Online (Sandbox Code Playgroud)
请注意:
保留最后一个换行符。
在stderr
被沉默到/dev/null
通过重定向命令整体块,但是读命令的返回状态被保留,如果需要处理读取错误的条件。
归档时间: |
|
查看次数: |
833210 次 |
最近记录: |