Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash脚本将参数传递给tcsh解释器_Bash_Csh_Tcsh - Fatal编程技术网

Bash脚本将参数传递给tcsh解释器

Bash脚本将参数传递给tcsh解释器,bash,csh,tcsh,Bash,Csh,Tcsh,这将需要一些bash和tcsh的知识。我想在bash脚本中添加一行代码,该代码使用一些参数调用命令,但使用tcsh解释器。假设我要调用的命令是ls(这很愚蠢,但它说明了问题)。因此,如果我的脚本包含: #!/bin/bash /bin/tcsh -c "ls"' "$*"' "${@}" 然后我称之为: my_script "first file" "second file" 我明白了: ls: first file second file: No such file or director

这将需要一些bash和tcsh的知识。我想在bash脚本中添加一行代码,该代码使用一些参数调用命令,但使用tcsh解释器。假设我要调用的命令是
ls
(这很愚蠢,但它说明了问题)。因此,如果我的脚本包含:

#!/bin/bash
/bin/tcsh -c "ls"' "$*"' "${@}"
然后我称之为:

my_script "first file" "second file"
我明白了:

ls: first file second file: No such file or directory

问题是tcsh只接收一个参数,
first file second file
,而不是两个参数。我该如何补救呢?

尽管有评论,但是
tcsh
没有直接的问题(相信我,我不是C shell的粉丝),bash本身也没有问题。事实上,如果将
tcsh
替换为
bash
,问题也会类似

问题是你想做的事情实际上非常难做。让我解释一下

bash
脚本中,您试图创建一个字符串,该字符串将包含一个有效的命令行,
tcsh
将正确解释该命令行,包括在参数中保留空格

逐步制定答案 让我们从一些简单的东西开始-参数中没有空格:

set -- /bin/ls /bin/sh /bin/bash   # Set the arguments to bash
/bin/tcsh -c "ls -l $*"
这将很好地工作;它将执行C shell,C shell将处理字符串并执行:

ls -l /bin/ls /bin/sh /bin/bash
因此,问题是当命令作为一个整体被指定为单个字符串时,如何将带有空格的参数可靠地传递给C shell

您已经知道这会遇到问题:

mkdir "./a b c" "./d e f"
set -- "a b c" "d e f"          # Two arguments with spaces
/bin/tcsh -c "ls -al $*"
在我的机器上,我得到:

ls: a: No such file or directory
ls: b: No such file or directory
ls: c: No such file or directory
ls: d: No such file or directory
ls: e: No such file or directory
ls: f: No such file or directory
如果我们手动进行扩展,我们可以通过以下方式获得所需的结果(对于这个有限的示例):

这将产生:

a b c:
total 0
drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:21 .
drwxr-xr-x  4 jleffler  staff  136 Aug 25 12:21 ..

d e f:
total 0
drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:21 .
drwxr-xr-x  4 jleffler  staff  136 Aug 25 12:21 ..
(我将假设两个目录“
abc
”和“
def
”从这里开始就存在,每次都不创建它们。)

因此,目标必须是找到一种方法来创建一个字符串,该字符串在由C shell自动(而不是如图所示手动)解释时是安全的。由于C shell具有元语法动物园(许多特殊字符),所以整个任务将很难完成,但让我们先完成简单的工作-空格,而不是元字符

对于每个参数,我们希望在开始和结束处添加单引号,并确保字符串中的任何单引号都受到保护。这是它自己的小党;技巧是用序列
'\'
替换嵌入的单引号,其中第一个单引号结束当前单引号字符串,反斜杠单引号嵌入单引号,最后一个单引号开始新的单引号字符串。我们希望将其添加到当前命令字符串的末尾。因此,这导致:

set -- "a b c" "d e f"          # Two arguments with spaces
cmd="ls -al"
for arg in "$@"
do escaped=$(sed -e "s/'/'\\''/g" -e "s/^/'/" -e "s/$/'/" <<< "$arg")
   cmd="$cmd $escaped"
done
echo "$cmd"
tcsh -c "$cmd"
好的,到目前为止,一切都很好。元语法动物园怎么样?幸运的是,大多数字符在单引号中没有特殊意义

是时候向列表中添加一些更复杂的目录了(这些目录也将在问题持续期间保留)。确保您知道正在创建的名称;你需要很好地理解壳牌的报价

作为练习,对于在本问题中创建的每个目录名,请编写替代项,这些替代项在用单引号括起来、用双引号括起来以及在整个参数周围没有任何引号时,都会给出相同的结果

$ mkdir '! % *' '$(pwd)' '`pwd`'
该脚本基本上没有变化-它使用shell glob生成目录名列表,依次回显每个参数,并列出inode编号:

set -- *
cmd="ls -ail"
for arg in "$@"
do echo "arg: $arg"
   escaped=$(sed -e "s/'/'\\''/g" -e "s/^/'/" -e "s/$/'/" <<< "$arg")
   cmd="$cmd $escaped"
done
echo "cmd: $cmd"
tcsh -c "$cmd"
正是医生吩咐的!但我们还不够残忍:正如Knuth所说,在测试代码时,你必须进入一种非常恶劣的刻薄心态,所以让我们试试:

$ mkdir "O'Reilly's Books"
$ mkdir "' \` \""
$ mkdir '${HOME}' '$PATH' 'He said, "Don'\''t Do It!"'
$ ls -l
total 0
drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:34 ! % *
drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:34 $(pwd)
drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:45 $PATH
drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:45 ${HOME}
drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:43 ' ` "
drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:45 He said, "Don't Do It!"
drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:43 O'Reilly's Books
drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:34 `pwd`
drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:21 a b c
drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:21 d e f
$ 
结果是:

arg: ! % *
arg: $(pwd)
arg: $PATH
arg: ${HOME}
arg: ' ` "
arg: He said, "Don't Do It!"
arg: O'Reilly's Books
arg: `pwd`
arg: a b c
arg: d e f
cmd: ls -ail '! % *' '$(pwd)' '$PATH' '${HOME}' '''' ` "' 'He said, "Don'''t Do It!"' 'O'''Reilly'''s Books' '`pwd`' 'a b c' 'd e f'
Unmatched `.
那不是我们想要的。但问题的一部分在于,在标记为“
cmd:
”的行中有4个单引号;它应该是
'\'
。因此,
sed
脚本不够准确

set -- *
cmd="ls -ail"
for arg in "$@"
do echo "arg: $arg"
   escaped=$(sed -e "s/'/'\\\\''/g" -e "s/^/'/" -e "s/$/'/" <<< "$arg")
   cmd="$cmd $escaped"
done
echo "cmd: $cmd"
tcsh -c "$cmd"
够意思吗?越来越近了。包含反斜杠的目录名呢

$ mkdir "a \\' \\\` \\$ b \\\" c"      # Make sure you do the exercise!
$ mkdir 'a \\'\'' \\\` \\$ b \\\" c'   # Make sure you do the exercise!
$ ls -li
total 8
1640119 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:34 ! % *
1640120 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:34 $(pwd)
1640176 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:45 $PATH
1640175 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:45 ${HOME}
1640163 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:43 ' ` "
1640177 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:45 He said, "Don't Do It!"
1640164 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:43 O'Reilly's Books
1640121 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:34 `pwd`
1640243 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:58 a \' \` \$ b \" c
1640259 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:01 a \\' \\\` \\$ b \\\" c
1640056 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:21 a b c
1640057 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:21 d e f
1640231 -rw-r--r--  1 jleffler  staff  223 Aug 25 12:56 x.sh
$ 
ls-ail
更改为
ls-dil
时,输出为:

$ bash x.sh
arg: ! % *
arg: $(pwd)
arg: $PATH
arg: ${HOME}
arg: ' ` "
arg: He said, "Don't Do It!"
arg: O'Reilly's Books
arg: `pwd`
arg: a \' \` \$ b \" c
arg: a \\' \\\` \\$ b \\\" c
arg: a b c
arg: d e f
arg: x.sh
cmd: ls -dil '! % *' '$(pwd)' '$PATH' '${HOME}' ''\'' ` "' 'He said, "Don'\''t Do It!"' 'O'\''Reilly'\''s Books' '`pwd`' 'a \'\'' \` \$ b \" c' 'a \\'\'' \\\` \\$ b \\\" c' 'a b c' 'd e f' 'x.sh'
1640119 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:34 ! % *
1640120 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:34 $(pwd)
1640176 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:45 $PATH
1640175 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:45 ${HOME}
1640163 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:43 ' ` "
1640177 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:45 He said, "Don't Do It!"
1640164 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:43 O'Reilly's Books
1640121 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:34 `pwd`
1640243 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:58 a \' \` \$ b \" c
1640259 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:01 a \\' \\\` \\$ b \\\" c
1640056 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:21 a b c
1640057 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:21 d e f
1640271 -rw-r--r--  1 jleffler  staff  223 Aug 25 13:03 x.sh
$ 
cmd: ls -dil '! % *' '$(pwd)' '$PATH' '${HOME}' ''\'' ` "' 'He said, "Don'\''t Do It!"' 'O'\''Reilly'\''s Books' '`pwd`' 'a
b
c' 'a b c' 'd e f' x.sh
178474064 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 ! % *
178474065 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 $(pwd)
178474219 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 $PATH
178474218 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 ${HOME}
178474170 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 ' ` "
178474220 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 He said, "Don't Do It!"
178474131 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 O'Reilly's Books
178474066 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 `pwd`
178474998 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:40 a?b?c
178473958 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 a b c
178473959 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 d e f
178475097 -rw-r--r--  1 jleffler  staff  115 Aug 25 13:41 x.sh
Unmatched '.
b: Command not found.
Unmatched '.
工作脚本 嗯,有一些原因可以解释为什么您永远不应该尝试解析来自
ls
的输出;它生成了问号来代替换行符(这在Mac OS X 10.8.1上,而不是GNU
ls
,只针对那些将分数留在家中的人;其他系统可能会有不同的行为)

当脚本(
x.sh
)运行时,我得到:

$ bash x.sh
arg: ! % *
arg: $(pwd)
arg: $PATH
arg: ${HOME}
arg: ' ` "
arg: He said, "Don't Do It!"
arg: O'Reilly's Books
arg: `pwd`
arg: a
b
c
arg: a \' \` \$ b \" c
arg: a \\' \\\` \\$ b \\\" c
arg: a b c
arg: d e f
arg: x.sh
cmd: ls -dil '! % *' '$(pwd)' '$PATH' '${HOME}' ''\'' ` "' 'He said, "Don'\''t Do It!"' 'O'\''Reilly'\''s Books' '`pwd`' 'a'
'b'
'c' 'a \'\'' \` \$ b \" c' 'a \\'\'' \\\` \\$ b \\\" c' 'a b c' 'd e f' 'x.sh'
ls: a: No such file or directory
1640119 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:34 ! % *
1640120 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:34 $(pwd)
1640176 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:45 $PATH
1640175 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:45 ${HOME}
1640163 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:43 ' ` "
1640177 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:45 He said, "Don't Do It!"
1640164 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:43 O'Reilly's Books
1640121 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:34 `pwd`
b: Command not found.
c: Command not found.
$
这里有很多问题。
sed
脚本分别处理参数的每一行。使用
sed
确实无法解决这一问题;或者,更准确地说,这不是我想用
sed
解决的问题。几年前,我编写了一个C程序
escape
来完成
sed
脚本几乎完成的工作

#!/bin/bash

set -- *
escaped=$(escape "$@")
cmd="ls -dil $escaped"
echo "cmd: $cmd"
bash -c "$cmd"
tcsh -c "$cmd"
注意,我在其中添加了对
bash
的调用。输出为:

$ bash x.sh
arg: ! % *
arg: $(pwd)
arg: $PATH
arg: ${HOME}
arg: ' ` "
arg: He said, "Don't Do It!"
arg: O'Reilly's Books
arg: `pwd`
arg: a \' \` \$ b \" c
arg: a \\' \\\` \\$ b \\\" c
arg: a b c
arg: d e f
arg: x.sh
cmd: ls -dil '! % *' '$(pwd)' '$PATH' '${HOME}' ''\'' ` "' 'He said, "Don'\''t Do It!"' 'O'\''Reilly'\''s Books' '`pwd`' 'a \'\'' \` \$ b \" c' 'a \\'\'' \\\` \\$ b \\\" c' 'a b c' 'd e f' 'x.sh'
1640119 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:34 ! % *
1640120 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:34 $(pwd)
1640176 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:45 $PATH
1640175 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:45 ${HOME}
1640163 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:43 ' ` "
1640177 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:45 He said, "Don't Do It!"
1640164 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:43 O'Reilly's Books
1640121 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:34 `pwd`
1640243 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:58 a \' \` \$ b \" c
1640259 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:01 a \\' \\\` \\$ b \\\" c
1640056 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:21 a b c
1640057 drwxr-xr-x  2 jleffler  staff   68 Aug 25 12:21 d e f
1640271 -rw-r--r--  1 jleffler  staff  223 Aug 25 13:03 x.sh
$ 
cmd: ls -dil '! % *' '$(pwd)' '$PATH' '${HOME}' ''\'' ` "' 'He said, "Don'\''t Do It!"' 'O'\''Reilly'\''s Books' '`pwd`' 'a
b
c' 'a b c' 'd e f' x.sh
178474064 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 ! % *
178474065 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 $(pwd)
178474219 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 $PATH
178474218 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 ${HOME}
178474170 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 ' ` "
178474220 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 He said, "Don't Do It!"
178474131 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 O'Reilly's Books
178474066 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 `pwd`
178474998 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:40 a?b?c
178473958 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 a b c
178473959 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 d e f
178475097 -rw-r--r--  1 jleffler  staff  115 Aug 25 13:41 x.sh
Unmatched '.
b: Command not found.
Unmatched '.
什么事?嗯,
bash
和其他派生自Bourne shell的shell,例如
ksh
,可以使用从一行开始并在其他行上继续的字符串,但C shell及其派生类则不行。他们要求在换行前加反斜杠。因此,要使用
tcsh
,我必须升级
escape
,以生成C shell的输出。一点也不难做到,但需要做到。据推测,这将是一个选项
-c
,并且为了通用安全,调用将变成:

escaped=$(escape -c -- "$@")
双破折号防止将
“$@”
中的参数误解为
转义的选项。在某种程度上,这表明很难编写脚本来处理包含可移植文件名字符集之外的字符的文件名。幸运的是,我不必经常处理C shell;我不打算让它成为escape的一部分,因为它是对
$ bash x.sh
arg: ! % *
arg: $(pwd)
arg: $PATH
arg: ${HOME}
arg: ' ` "
arg: He said, "Don't Do It!"
arg: O'Reilly's Books
arg: `pwd`
arg: a
b
c
arg: a \' \` \$ b \" c
arg: a \\' \\\` \\$ b \\\" c
arg: a b c
arg: d e f
arg: x.sh
cmd: ls -dil '! % *' '$(pwd)' '$PATH' '${HOME}' ''\'' ` "' 'He said, "Don'\''t Do It!"' 'O'\''Reilly'\''s Books' '`pwd`' 'a'
'b'
'c' 'a \'\'' \` \$ b \" c' 'a \\'\'' \\\` \\$ b \\\" c' 'a b c' 'd e f' 'x.sh'
ls: a: No such file or directory
1640119 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:34 ! % *
1640120 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:34 $(pwd)
1640176 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:45 $PATH
1640175 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:45 ${HOME}
1640163 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:43 ' ` "
1640177 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:45 He said, "Don't Do It!"
1640164 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:43 O'Reilly's Books
1640121 drwxr-xr-x  2 jleffler  staff  68 Aug 25 12:34 `pwd`
b: Command not found.
c: Command not found.
$
#!/bin/bash

set -- *
escaped=$(escape "$@")
cmd="ls -dil $escaped"
echo "cmd: $cmd"
bash -c "$cmd"
tcsh -c "$cmd"
cmd: ls -dil '! % *' '$(pwd)' '$PATH' '${HOME}' ''\'' ` "' 'He said, "Don'\''t Do It!"' 'O'\''Reilly'\''s Books' '`pwd`' 'a
b
c' 'a b c' 'd e f' x.sh
178474064 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 ! % *
178474065 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 $(pwd)
178474219 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 $PATH
178474218 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 ${HOME}
178474170 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 ' ` "
178474220 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 He said, "Don't Do It!"
178474131 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 O'Reilly's Books
178474066 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 `pwd`
178474998 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:40 a?b?c
178473958 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 a b c
178473959 drwxr-xr-x  2 jleffler  staff   68 Aug 25 13:38 d e f
178475097 -rw-r--r--  1 jleffler  staff  115 Aug 25 13:41 x.sh
Unmatched '.
b: Command not found.
Unmatched '.
escaped=$(escape -c -- "$@")
#!/bin/bash
/bin/tcsh -c 'ls "$1" "$2"' "$@"
/bin/tcsh -c "ls "'$argv:q' "${@}"