[英]how to pass asterisk into ls command inside bash script
Hi… Need a little help here… 嗨...这里需要一点帮助......
I tried to emulate the DOS' dir
command in Linux using bash script. 我尝试使用bash脚本在Linux中模拟DOS的dir
命令。 Basically it's just a wrapped ls
command with some parameters plus summary info. 基本上它只是一个包含ls
命令,带有一些参数和摘要信息。 Here's the script: 这是脚本:
#!/bin/bash
# default to current folder
if [ -z "$1" ]; then var=.;
else var="$1"; fi
# check file existence
if [ -a "$var" ]; then
# list contents with color, folder first
CMD="ls -lgG $var --color --group-directories-first"; $CMD;
# sum all files size
size=$(ls -lgGp "$var" | grep -v / | awk '{ sum += $3 }; END { print sum }')
if [ "$size" == "" ]; then size="0"; fi
# create summary
if [ -d "$var" ]; then
folder=$(find $var/* -maxdepth 0 -type d | wc -l)
file=$(find $var/* -maxdepth 0 -type f | wc -l)
echo "Found: $folder folders "
echo " $file files $size bytes"
fi
# error message
else
echo "dir: Error \"$var\": No such file or directory"
fi
The problem is when the argument contains an asterisk (*), the ls
within the script acts differently compare to the direct ls
command given at the prompt. 问题是,当参数包含星号(*)的ls
脚本内不同行为比较直接的ls
命令在提示发出。 Instead of return the whole files list, the script only returns the first file. 该脚本仅返回第一个文件,而不是返回整个文件列表。 See the video below to see the comparation in action. 请参阅下面的视频,了解实际比较情况。 I don't know why it behaves like that. 我不知道它为什么会这样。
Anyone knows how to fix it? 任何人都知道如何解决它? Thank you. 谢谢。
Video: problem in action 视频: 行动中的问题
UPDATE : 更新 :
The problem has been solved. 问题已经解决了。 Thank you all for the answers. 谢谢大家的答案。 Now my script works as expected. 现在我的脚本按预期工作了。 See the video here: http://i.giphy.com/3o8dp1YLz4fIyCbOAU.gif 观看视频: http : //i.giphy.com/3o8dp1YLz4fIyCbOAU.gif
The asterisk *
is expanded by the shell when it parses the command line. 在解析命令行时,shell会扩展星号*
。 In other words, your script doesn't get a parameter containing an asterisk, it gets a list of files as arguments. 换句话说,您的脚本没有获得包含星号的参数,它获取文件列表作为参数。 Your script only works with $1
, the first argument. 您的脚本仅适用于$1
,即第一个参数。 It should work with "$@"
instead. 它应该与"$@"
使用。
This is because when you retrieve $1
you assume the shell does NOT expand *
. 这是因为当你检索$1
你认为shell不会扩展*
。
In fact, when *
(or other glob) matches, it is expanded, and broken into segments by $IFS
, and then passed as $1
, $2
, etc. 事实上,当*
(或其他glob)匹配时,它会被扩展,并被$IFS
分成段,然后传递为$1
, $2
等。
You're lucky if you simply retrieved the first file. 如果您只是检索第一个文件,那就太幸运了。 When your first file's path contains spaces, you'll get an error because you only get the first segment before the space. 当您的第一个文件的路径包含空格时,您将收到错误,因为您只获得空格之前的第一个段。
Seriously, read this and especially this . 说真的,读这个 ,特别是这个 。 Really. 真。
And please don't do things like 请不要做像这样的事情
CMD=whatever you get from user input; $CMD;
You are begging for trouble. 你在乞求麻烦。 Don't execute arbitrary string from the user. 不要从用户执行任意字符串。
Both above answers already answered your question. 以上两个答案都已经回答了你的问题 So, i'm going a bit more verbose. 所以,我会更加冗长。
In your terminal is running the bash
interpreter (probably). 在您的终端中运行bash
解释器(可能)。 This is the program which parses your input line(s) and doing "things" based on your input. 这是一个程序,它根据您的输入解析您的输入行和做“事情”。
When you enter some line the bash
start doing the following workflow: 当你输入一些行时, bash
开始执行以下工作流程:
Only after all above the bash
毕竟只有在bash
上面
ls
or dir.sh
... etc., 将执行一些外部命令,如ls
或dir.sh
......等, builtins
like echo
, for
, if
etc... 或者将对已知关键字和builtins
执行一些“内部”操作,如echo
, for
, if
等... As you can see, the second last is the filename generation (globbing) . 如您所见,倒数第二个是文件名生成(globbing) 。 So, in your case - if the test*
matches some files, your bash
expands the willcard characters (aka does the globbing). 所以,在你的情况下 - 如果test*
匹配某些文件,你的bash
会扩展 willcard字符(也就是全局)。
So, 所以,
dir.sh test*
, 当你输入dir.sh test*
, test*
matches some files 并且 test*
匹配一些文件 dir.sh
with already expanded filenames 然后将执行带有已扩展文件名的命令dir.sh
dir.sh test.pas test.swift
例如,脚本执行(在您的情况下)为: dir.sh test.pas test.swift
BTW, it acts exactly with the same way for your ls
example: 顺便说一句,它为您以同样的方式正好充当ls
例如:
bash
expands the ls test*
to ls test.pas test.swift
bash
将ls test*
扩展为ls test.pas test.swift
ls
with the above two arguments 然后用上面两个参数执行ls
ls
will print the result for the got two arguments. 并且ls
将打印获得两个参数的结果。 ls
don't even see the test*
argument - if it is possible - the bash
expands the wilcard characters. 换句话说, ls
甚至没有看到test*
参数 - 如果可能的话 - bash
扩展了wilcard字符。 ( *
and ?
). ( *
和?
)。 Now back to your script: add after the shebang the following line: 现在回到你的脚本:在shebang之后添加以下行:
echo "the $0 got this arguments: $@"
and you will immediatelly see, the real argumemts how your script got executed. 并且你会立即看到,真正的争论是你的脚本如何被执行。
also, in such cases is a good practice trying to execute the script in debug-mode, eg 此外,在这种情况下尝试以调试模式执行脚本是一种很好的做法,例如
bash -x dir.sh test*
and you will see, what the script does exactly. 你会看到,剧本的确是什么。
Also, you can do the same for your current interpreter, eg just enter into the terminal 此外,您可以为当前的解释器执行相同的操作,例如,只需进入终端即可
set -x
and try run the dir.sh test*
= and you will see, how the bash
will execute the dir.sh
command. 并尝试运行dir.sh test*
=你会看到bash
将如何执行dir.sh
命令。 (to stop the debug mode, just enter set +x
) (要停止调试模式,只需输入set +x
)
Everbody is giving you valuable advice which you should definitely should follow! Everbody正在为您提供宝贵的建议,您应该遵循这些建议!
But here is the real answer to your question. 但这是你问题的真正答案。
To pass unexpanded arguments to any executable you need to single quote them: 要将未展开的参数传递给任何可执行文件,您需要单引号:
./your_script '*'
The best solution I have is to use the eval command, in this way: 我有的最好的解决方案是使用eval命令,这样:
#!/bin/bash
cmd="some command \"with_quetes_and_asterisk_in_it*\""
echo "$cmd"
eval $cmd
The eval command takes its arguments and evaluates them into the command as the shell does. eval命令获取其参数并将其评估为shell中的命令。 This solves my problem when I need to call a command with asterisk '*' in it from a script. 当我需要从脚本中调用带有星号'*'的命令时,这解决了我的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.