Answers:
如果您的shell是bash(以及其他),则快捷方式$(cat afile)
是$(< afile)
,因此您应编写:
mycommand "$(< file.txt)"
在“命令替换”部分的bash手册页中记录。
或者,从stdin中读取命令,因此: mycommand < file.txt
<
操作符不是捷径。这意味着外壳本身将执行重定向,而不是cat
为其重定向属性执行二进制文件。
"$(…)"
,则的内容file.txt
将传递给的标准输入mycommand
,而不作为参数。"$(…)"
表示运行命令并以字符串形式返回输出 ; 在这里,“命令”仅读取文件,但可能更复杂。
如前所述,您可以使用反引号或$(cat filename)
。
没有提到的,并且我认为需要注意的是,您必须记住,shell会根据空格将文件的内容分开,并将找到的每个“单词”作为参数提供给命令。尽管您可以将命令行参数括在引号中,以便它可以包含空格,转义序列等,但是从文件读取将不会做同样的事情。例如,如果您的文件包含:
a "b c" d
您将得到的参数是:
a
"b
c"
d
如果您希望将每一行作为参数,请使用while / read / do构造:
while read i ; do command_name $i ; done < filename
read -r
除非您要扩展反斜杠转义序列,否则应该为Read。NUL是比换行符更安全的定界符,尤其是当您传递的参数是文件名之类的东西时,其中可以包含文字换行符。另外,如果不清除IFS,则会从中隐式清除前导和尾随空格i
。
command `< file`
会将文件内容传递给stdin上的命令,但会删除换行符,这意味着您无法单独遍历每行。为此,您可以编写一个带有“ for”循环的脚本:
for line in `cat input_file`; do some_command "$line"; done
或(多行变体):
for line in `cat input_file`
do
some_command "$line"
done
或(多行变体,使用$()
代替``
):
for line in $(cat input_file)
do
some_command "$line"
done
< file
反引号意味着它实际上根本不会执行重定向command
。
command `< file`
不起作用; zsh是另一回事,但这不是此问题所针对的shell)。
Hello World
一条线上。您会首先看到它some_command Hello
,然后some_command World
,不是 some_command "Hello World"
或some_command Hello World
。
您可以使用反引号:
echo World > file.txt
echo Hello `cat file.txt`
echo "Hello * Starry * World" > file.txt
的第一个步骤,你会得到传递给第二个命令至少四个单独的参数-而且可能,因为*
s会扩展为当前目录中存在的文件名。
fork()
关闭一个子容器,并在其stdout上附加了FIFO,然后/bin/cat
作为该子壳的子级进行调用,然后通过FIFO读取输出;与相比$(<file.txt)
,它直接将文件的内容读取到bash中,而不涉及子shell或FIFO。
如果您想以一种健壮的方式来执行此操作,以使其适用于每个可能的命令行参数(带空格的值,带换行的值,带文字引号字符的值,不可打印的值,带glob字符的值等),它会有点更有趣的。
在给定参数数组的情况下写入文件:
printf '%s\0' "${arguments[@]}" >file
... 适当地用"argument one"
,"argument two"
等替换。
要读取该文件并使用其内容(在bash,ksh93或另一个带有数组的最新shell中):
declare -a args=()
while IFS='' read -r -d '' item; do
args+=( "$item" )
done <file
run_your_command "${args[@]}"
要读取该文件并使用其内容(在没有数组的shell中;请注意,这会覆盖您的本地命令行参数列表,因此最好在函数内部完成,这样就覆盖了函数的参数,而不是全球清单):
set --
while IFS='' read -r -d '' item; do
set -- "$@" "$item"
done <file
run_your_command "$@"
请注意-d
(允许使用不同的行尾定界符)是非POSIX扩展,并且没有数组的shell也可能不支持它。在这种情况下,您可能需要使用非Shell语言将NUL分隔的内容转换为eval
-safe形式:
quoted_list() {
## Works with either Python 2.x or 3.x
python -c '
import sys, pipes, shlex
quote = pipes.quote if hasattr(pipes, "quote") else shlex.quote
print(" ".join([quote(s) for s in sys.stdin.read().split("\0")][:-1]))
'
}
eval "set -- $(quoted_list <file)"
run_your_command "$@"
这是我将文件内容作为参数传递给命令的方式:
./foo --bar "$(cat ./bar.txt)"
$(<bar.txt)
(使用带适当扩展名的shell(如bash)时)。$(<foo)
这是一种特殊情况:与中使用的常规命令替换不同$(cat ...)
,它不会派生子shell来进行操作,因此避免了很多开销。
在我的bash外壳中,以下内容就像一个咒语:
cat input_file | xargs -I % sh -c 'command1 %; command2 %; command3 %;'
其中input_file是
arg1
arg2
arg3
显而易见,这使您可以从input_file的每一行执行多个命令,这是我在此处学到的一个不错的小技巧。
$(somecommand)
,您将执行该命令而不是将其作为文本传递。同样地,>/etc/passwd
将被处理为重定向和重写/etc/passwd
(如果具有适当权限运行)等
xargs -d $'\n' sh -c 'for arg; do command1 "$arg"; command2 "arg"; command3 "arg"; done' _
-而且效率更高,因为它会将尽可能多的参数传递给每个shell,而不是在输入文件中每行启动一个shell。
在几次编辑@Wesley Rice的答案后,我认为我的更改太大了,无法继续更改他的答案,而不是自己编写。因此,我决定需要自己编写!
读入文件的每一行并逐行对其进行操作,如下所示:
#!/bin/bash
input="/path/to/txt/file"
while IFS= read -r line
do
echo "$line"
done < "$input"
这直接来自作者Vivek Gite,网址为:https : //www.cyberciti.biz/faq/unix-howto-read-line-by-line-from-file/。他获得了荣誉!
语法:在Bash Unix&Linux shell上逐行读取文件:
1. bash,ksh,zsh和所有其他Shell的语法如下,以逐行
2 读取文件while read -r line; do COMMAND; done < input.file
。3.-r
传递给read命令的选项防止反斜杠转义被解释。
4.IFS=
在读取命令前添加选项,以防止前导/后缀空白被修剪
-5。while IFS= read -r line; do COMMAND_on $line; done < input.file
现在,我要回答这个已经关闭的问题:是否可以通过git add从文件中添加文件列表?-这是我的答案:
请注意,这FILES_STAGED
是一个包含文件绝对路径的变量,该文件包含一堆行,其中每一行都是我要执行的文件的相对路径git add
。此代码段即将成为该项目中“ eRCaGuy_dotfiles / useful_scripts / sync_git_repo_to_build_machine.sh”文件的一部分,以使开发中的文件能够轻松地从一台PC(例如,我编写过代码的计算机)同步到另一台PC(例如:我构建的功能更强大的计算机):https : //github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles。
while IFS= read -r line
do
echo " git add \"$line\""
git add "$line"
done < "$FILES_STAGED"
git add
以下操作:是否可以从文件中“ git add”文件列表?