#!/bin/sh
while read LINE
do
echo $LINE
done <$1
echo 11111-----------
echo $LINE
在我的脚本中,我可以将文件名作为参数。例如,如果文件包含“aaaa”,那么它会打印出这个:
aaaa
11111-----
但是这只是把文件打印到屏幕上,我想将它保存到变量中! 有没有简单的方法可以做到这一点?
sh
中,您可以使用:#!/bin/sh
value=`cat config.txt`
echo "$value"
#!/bin/bash
value=$(<config.txt)
echo "$value"
bash
或zsh
中的cat
命令来读取文件被认为是无用的Cat用法。value="`cat config.txt`"
和value="$(<config.txt)"
更安全,这样做不会改变原来的意思。 - Martin von Wittichcat
并不总是被认为是无用的。例如,< invalid-file 2>/dev/null
会导致无法将错误信息路由到 /dev/null
,而 cat invalid-file 2>/dev/null
则可以正确地路由到 /dev/null
。 - Dejay Claytonvalue=$(<config.txt)
是正确的,但value = $(<config.txt)
是错误的。注意那些空格。 - ArtHare{ var=$(<"$file"); } 2>/dev/null
жқҘзҰҒз”ЁиӯҰе‘ҠпјҢеҸӮиҖғhttps://unix.stackexchange.com/questions/428500/how-to-make-bash-substitution-filename-silent/428529#428529гҖӮ - rudimeier两个重要的陷阱
到目前为止其他答案忽略了这两个陷阱:
从命令扩展中删除尾随换行符
这是一个问题,适用于:
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 字符
在 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
软件包)... 我没有看到bash中有关于<()
替换扩展的POSIX 7替代方案,除了写入另一个文件...
当然,这样做效率低下且不方便,所以我的建议是:如果输入文件可能包含NUL字符,请不要使用Bash。
S="$(printf "\\\'\"")"; echo $S
。输出:\'"
。所以它可以工作 =) - Ciro Santilli OurBigBook.com$()
扩展,我的例子表明$()
扩展与\''"
一起使用。 - Ciro Santilli OurBigBook.com如果您想将整个文件读入变量中:
#!/bin/bash
value=`cat sources.xml`
echo $value
如果您想逐行读取它:
while read line; do
echo $line
done < file.txt
echo "$value"
中应该使用双引号引用变量,否则shell将对该值执行空格分词和通配符扩展。 - tripleeeread -r
,而不是仅仅使用read
,除非你需要特定的旧行为。这样能够使代码更加规范,并避免出现一些奇怪的问题。 - tripleeev=$(cat <file_path>)
echo $v
<file_path>
意思是 在此输入您的文件路径
。 - angelo.mastro使用bash时,您可以像这样使用read
:
#!/usr/bin/env bash
{ IFS= read -rd '' value <config.txt;} 2>/dev/null
printf '%s' "$value"
请注意:
最后一个换行符被保留。
通过重定向整个命令块,使stderr
被静音为/dev/null
,但读取命令的返回状态被保留,如果需要处理读取错误条件。
正如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://dev59.com/zWs05IYBdhLWcg3wIedj#22607352
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"
}
$ read_input file_contents < /tmp/file
# $file_contents now contains the contents of /tmp/file
_contents="${_contents}${_line}\n "
这样的东西来保留换行符呢? - Eenoku$'\n'
吗?这是必要的,否则你将会添加 \
和 n
字符。你的代码块末尾还有一个额外的空格,不确定这是否是有意为之,但是它会导致每一行都多了一个空格的缩进。 - dimo414我使用:
NGINX_PID=`cat -s "/sdcard/server/nginx/logs/nginx.pid" 2>/dev/null`
if [ "$NGINX_PID" = "" ]; then
echo "..."
exit
fi
所有给出的解决方案都非常缓慢,因此:
mapfile -d '' content </etc/passwd # Read file into an array
content="${content[*]%$'\n'}" # Remove trailing newline
希望能更加优化它,但我想不出更多的方法。
更新:找到了一种更快的方法。
read -rd '' content </etc/passwd
这将返回1
的退出代码,如果您希望它始终为0
:
read -rd '' content </etc/passwd || :
你可以通过for循环逐行访问
#!/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
将整个内容复制到文件中(比如说line.sh);执行
chmod +x line.sh
./line.sh
for
循环不是按行循环,而是按单词循环。在 /etc/passwd
的情况下,每行只包含一个单词。但是,其他文件可能每行包含多个单词。 - mpb
cat
或$(<someFile)
的结果会导致输出不完整(大小小于实际文件)。 - Aquarius Power