使用变量作为命令的输入
Using variables as the input to command
我搜索了各种留言板以了解为什么在某些情况下我不能使用变量作为命令的输入。它是 STDIN issue/limitation 吗?为什么使用 echo
和此处的字符串可以解决问题?
例如,
~$ myvar=$(ls -l)
~$ grep Jan "$myvar"
grep: total 9
-rwxr-xr-x 1 jvp jvp 561 Feb 2 23:59 directoryscript.sh
-rw-rw-rw- 1 jvp jvp 0 Jan 15 10:30 example1
drwxrwxrwx 2 jvp jvp 0 Jan 19 21:54 linuxtutorialwork
-rw-rw-rw- 1 jvp jvp 0 Jan 15 13:08 littlefile
-rw-rw-rw- 1 jvp jvp 0 Jan 19 21:54 man
drwxrwxrwx 2 jvp jvp 0 Feb 2 20:33 projectbackups
-rwxr-xr-x 1 jvp jvp 614 Feb 2 20:41 projectbackup.sh
drwxrwxrwx 2 jvp jvp 0 Feb 2 20:32 projects
-rw-rw-rw- 1 jvp jvp 0 Jan 19 21:54 test1
-rw-rw-rw- 1 jvp jvp 0 Jan 19 21:54 test2
-rw-rw-rw- 1 jvp jvp 0 Jan 19 21:54 test3: File name too long
如你所见,我得到了错误... 'File name too long'
现在,我可以使用以下任一方法来实现它:
echo "$myvar" | grep Jan
grep Jan <<< "$myvar"
但是,我真的很想更好地理解为什么会这样。也许我遗漏了一些关于命令替换的基础知识或者什么是可接受的 STDIN 形式。
Grep 将命令行参数文件作为命令行参数,而不是直接的字符串。您确实需要 echo
在您的变量中进行 grep 搜索。
我认为这里存在对 Unix tools/Bash 运作方式的根本误解。
您在这里尝试做的似乎是将 ls
的输出存储在一个变量中(出于其他原因您不应该这样做)并尝试 grep
使用 grep.
存储在该变量中的字符串
这不是 grep 的工作方式。如果您查看 man page for grep,它表示:
SYNOPSIS
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
DESCRIPTION
grep searches the named input FILEs for lines containing a match to
the given PATTERN. If no files are specified, or if the file “-” is
given, grep searches standard input. By default, grep prints the
matching lines.
请注意,它明确表示“grep 搜索命名输入 FILEs”。
然后它继续说“如果没有指定文件[...] grep 搜索标准输入”。
换句话说,根据定义 grep
不搜索字符串。它搜索文件。因此,您不能通过 bash 变量传递 grep
字符串。
当您输入时
grep Jan "$myvar"
根据语法,grep 认为 "Jan" 是 PATTERN,而 "$myvar" 中的 entire 字符串是一个 FILEname。因此错误 File name too long
.
当你写
echo "$myvar" | grep Jan
您现在正在做的是bash将“$myvar”的内容输出到标准输出。 bash 中的 |
(管道运算符)将 echo
命令的 stdout(标准输出)连接到 grep
命令的 stdin(标准输入)。如上所述,当您省略 grep
的 FILEname 参数时,默认情况下它会在 stdin 中搜索字符串,这就是它起作用的原因。
grep
实用程序可以运行...
- 在命令行提供名称的文件上,在用于匹配的正则表达式之后
- 在其标准输入上提供的流上。
您正在这样做:
myvar=$(ls -l)
grep Jan "$myvar"
这将变量 myvar
的内容作为参数提供给 grep
命令,由于它不是文件名,因此不起作用。
有很多方法可以实现您的目标。这里有几个例子。
使用变量的内容作为连接到 grep
的标准输入的流,使用以下方法之一(都提供相同的输出):
grep Jan <<<"$myvar"
echo "$myvar" | grep Jan
grep Jan < <(echo "$myvar")
避免以变量开头,将ls
的输出直接发送给grep:
ls -l | grep Jan
grep Jan < <(ls -l)
提供 grep
实际上是文件名的表达式:
grep Jan <(ls -l)
<(ls -l)
表达式是导致创建 FIFO (first-in first-out) 特殊文件的语法。 ls -l
命令将其输出发送到 FIFO。表达式由 Bash 转换为可用于读取的实际文件名。
为了消除任何混淆,下面的两个陈述(已在上面显示)看起来很相似,但根本上有很大不同:
grep Jan <(ls -l)
grep Jan < <(ls -l)
在第一个中,grep
接收一个文件名作为参数并读取该文件。在第二种情况下,额外的 <
(两个 <
之间的空格很重要)创建一个重定向,读取 FIFO 并将其输出提供给 grep
的标准输入。两种情况下都有一个 FIFO,但它以完全不同的方式呈现给命令。
我搜索了各种留言板以了解为什么在某些情况下我不能使用变量作为命令的输入。它是 STDIN issue/limitation 吗?为什么使用 echo
和此处的字符串可以解决问题?
例如,
~$ myvar=$(ls -l)
~$ grep Jan "$myvar"
grep: total 9
-rwxr-xr-x 1 jvp jvp 561 Feb 2 23:59 directoryscript.sh
-rw-rw-rw- 1 jvp jvp 0 Jan 15 10:30 example1
drwxrwxrwx 2 jvp jvp 0 Jan 19 21:54 linuxtutorialwork
-rw-rw-rw- 1 jvp jvp 0 Jan 15 13:08 littlefile
-rw-rw-rw- 1 jvp jvp 0 Jan 19 21:54 man
drwxrwxrwx 2 jvp jvp 0 Feb 2 20:33 projectbackups
-rwxr-xr-x 1 jvp jvp 614 Feb 2 20:41 projectbackup.sh
drwxrwxrwx 2 jvp jvp 0 Feb 2 20:32 projects
-rw-rw-rw- 1 jvp jvp 0 Jan 19 21:54 test1
-rw-rw-rw- 1 jvp jvp 0 Jan 19 21:54 test2
-rw-rw-rw- 1 jvp jvp 0 Jan 19 21:54 test3: File name too long
如你所见,我得到了错误... 'File name too long'
现在,我可以使用以下任一方法来实现它:
echo "$myvar" | grep Jan
grep Jan <<< "$myvar"
但是,我真的很想更好地理解为什么会这样。也许我遗漏了一些关于命令替换的基础知识或者什么是可接受的 STDIN 形式。
Grep 将命令行参数文件作为命令行参数,而不是直接的字符串。您确实需要 echo
在您的变量中进行 grep 搜索。
我认为这里存在对 Unix tools/Bash 运作方式的根本误解。
您在这里尝试做的似乎是将 ls
的输出存储在一个变量中(出于其他原因您不应该这样做)并尝试 grep
使用 grep.
这不是 grep 的工作方式。如果您查看 man page for grep,它表示:
SYNOPSIS grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...] DESCRIPTION grep searches the named input FILEs for lines containing a match to the given PATTERN. If no files are specified, or if the file “-” is given, grep searches standard input. By default, grep prints the matching lines.
请注意,它明确表示“grep 搜索命名输入 FILEs”。 然后它继续说“如果没有指定文件[...] grep 搜索标准输入”。
换句话说,根据定义 grep
不搜索字符串。它搜索文件。因此,您不能通过 bash 变量传递 grep
字符串。
当您输入时
grep Jan "$myvar"
根据语法,grep 认为 "Jan" 是 PATTERN,而 "$myvar" 中的 entire 字符串是一个 FILEname。因此错误 File name too long
.
当你写
echo "$myvar" | grep Jan
您现在正在做的是bash将“$myvar”的内容输出到标准输出。 bash 中的 |
(管道运算符)将 echo
命令的 stdout(标准输出)连接到 grep
命令的 stdin(标准输入)。如上所述,当您省略 grep
的 FILEname 参数时,默认情况下它会在 stdin 中搜索字符串,这就是它起作用的原因。
grep
实用程序可以运行...
- 在命令行提供名称的文件上,在用于匹配的正则表达式之后
- 在其标准输入上提供的流上。
您正在这样做:
myvar=$(ls -l)
grep Jan "$myvar"
这将变量 myvar
的内容作为参数提供给 grep
命令,由于它不是文件名,因此不起作用。
有很多方法可以实现您的目标。这里有几个例子。
使用变量的内容作为连接到 grep
的标准输入的流,使用以下方法之一(都提供相同的输出):
grep Jan <<<"$myvar"
echo "$myvar" | grep Jan
grep Jan < <(echo "$myvar")
避免以变量开头,将ls
的输出直接发送给grep:
ls -l | grep Jan
grep Jan < <(ls -l)
提供 grep
实际上是文件名的表达式:
grep Jan <(ls -l)
<(ls -l)
表达式是导致创建 FIFO (first-in first-out) 特殊文件的语法。 ls -l
命令将其输出发送到 FIFO。表达式由 Bash 转换为可用于读取的实际文件名。
为了消除任何混淆,下面的两个陈述(已在上面显示)看起来很相似,但根本上有很大不同:
grep Jan <(ls -l)
grep Jan < <(ls -l)
在第一个中,grep
接收一个文件名作为参数并读取该文件。在第二种情况下,额外的 <
(两个 <
之间的空格很重要)创建一个重定向,读取 FIFO 并将其输出提供给 grep
的标准输入。两种情况下都有一个 FIFO,但它以完全不同的方式呈现给命令。