Linux 在 shell 脚本中列出文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9940688/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Listing files in shell script
提问by Akhil Thayyil
When i try the below code am getting all files whose filename starts with E
当我尝试下面的代码时,我正在获取文件名以 E 开头的所有文件
#!/bin/bash
data=$(ls -trh E*)
for entry in ${data}
do
echo ${entry}
done
But if i try the below code , which get the wildcard from argument , i am getting only the first filename
但是如果我尝试下面的代码,它从参数中获取通配符,我只得到第一个文件名
#!/bin/bash
data=$(ls -trh )
for entry in ${data}
do
echo ${entry}
done
Can anyone help me to solve this ..
谁能帮我解决这个..
When i gave quotes like this myscript.sh 'E*' it worked fine , is there any way to do this without giving quotes ?
当我给出这样的引号时 myscript.sh 'E*' 它工作正常,有没有办法在不给出引号的情况下做到这一点?
采纳答案by brice
This is a shell expansion problem.
这是一个shell扩展问题。
Your shell will interpret wildcard characters before passing then to your process. For example:
您的 shell 将在传递给您的进程之前解释通配符。例如:
script.sh
脚本文件
#!/bin/bash
echo
Running the above with a wildcard:
使用通配符运行上述内容:
> ./script.sh E*
Eva Eve Evolve
If you want to pass an argument without shell interpreting it first, you will have to quote it:
如果你想在没有 shell 解释的情况下传递一个参数,你必须引用它:
> ./script.sh 'E*'
E*
Better Solution using find
:
更好的解决方案使用find
:
What you're actually trying to do is get a list of all files and folders in a given directory, in reverse modification time order (oldest first). The output of ls
is notoriously painful to parse. It is preferable to use the powerful and flexible find
command instead.
您实际上想要做的是获取给定目录中所有文件和文件夹的列表,按反向修改时间顺序(最旧的在前)。的输出ls
是众所周知的解析痛苦。最好使用强大而灵活的find
命令。
This is a one liner:
这是一个单班轮:
> find ./ -maxdepth 1 -printf "%A@ %f> ls -l
total 4296
drwxr-xr-x 2 bfer cvs 4096 2012-03-05 15:49 colortry
drwxr-xr-x 3 bfer cvs 4096 2012-03-27 15:05 githug
drwxr-xr-x 3 bfer cvs 4096 2012-03-12 17:18 hooks-bare
drwxr-xr-x 3 bfer cvs 4096 2012-03-28 12:38 java
-rw-r--r-- 1 bfer cvs 4025413 2012-03-27 12:53 mozdebug
drwxr-xr-x 2 bfer cvs 4096 2012-02-16 12:54 mustache_bug_demo
-rwxr-xr-x 1 bfer cvs 113 2012-03-30 12:20 try.sh
> find ./ -maxdepth 1 -printf "%A@ %f> curl example.com/site?q=hello&name=bob
> echo 23/(7/98) | bc
" | sort -z -n | while read -d '' date line; do echo "$line"; done
mozdebug
colortry
hooks-bare
mustache_bug_demo
githug
java
try.sh
./
" | sort -z -n | while read -d '' date line; do echo "$line"; done
Which is probably cryptic, but makes sense once explained.
这可能是神秘的,但一旦解释就有意义了。
- Find all files in this directory without recursing
find ./ -maxdepth 1
- For each file, print out their last modified time in second
-printf "%A@
- and their filename, separated by null characters
%f\0"
- Sort the null-separated strings by last modified time (numerically)
sort -z -n
- For every null separated string assign the timestamp to 'date' and the rest of the line to 'line':
while read -d '' date line
- Print the line
echo "$line"
- 不递归地查找此目录中的所有文件
find ./ -maxdepth 1
- 对于每个文件,以秒为单位打印出他们上次修改的时间
-printf "%A@
- 和它们的文件名,用空字符分隔
%f\0"
- 按最后修改时间(数字)对空分隔的字符串进行排序
sort -z -n
- 对于每个空分隔的字符串,将时间戳分配给“日期”,将行的其余部分分配给“行”:
while read -d '' date line
- 打印行
echo "$line"
For example, in my directory:
例如,在我的目录中:
> curl "example.com/site?q=hello&name=bob"
> echo "23/(7/98)" | bc
If you don't want the ./
result, just take it out of your final set.
如果您不想要./
结果,只需将其从最终设置中取出即可。
updated:With Sorpigal's suggestion to handle filenames with newlines.
更新:Sorpigal 建议使用换行符处理文件名。
Further note on shell expansion
关于外壳扩展的进一步说明
This is the same with things like parenthesis and ampersands. For example, the following curl commands will not work as expected:
这与括号和与号等内容相同。例如,以下 curl 命令将无法按预期工作:
bash yourscript.sh 'E*'
As the ampersand and parentheses will be interpreted by the shell before they are passed to the process as arguments.
因为 & 号和括号在作为参数传递给进程之前将由 shell 解释。
For this to work correctly, you will have to quote the args:
为了使其正常工作,您必须引用参数:
./script "E*"
回答by Andreas Wong
Did you enclose your wildcard when calling your script?
调用脚本时是否附上了通配符?
#!/bin/bash
data=$(ls -trh "$@" | cat -E)
while [ ${#data} != 0 ]
do
echo ${data%%$*}
data=${data#*$}
done
Otherwise your script will get things that start with E in your current directory and $1 becomes exactly the first file, thus the behavior
否则,您的脚本将在当前目录中获取以 E 开头的内容,而 $1 恰好成为第一个文件,因此行为
回答by Sandeep Pathak
This sound like a Shell Expansion problem . If you want to pass wild card to a shell , just quote it . eg .
这听起来像壳扩展问题。如果您想将通配符传递给 shell,只需引用它。例如。
#!/usr/bin/env bash
pat=""
while IFS= read -r -d '' file ; do
echo "$file"
done < <(find . -maxdepth 1 -name "$pat" -print0)
Quoting would avoid shell expansion .
引用将避免 shell 扩展。
回答by pizza
Try this.
尝试这个。
myscript.sh E\*
回答by sorpigal
You should not be using ls
in a shell script. The output of ls
is for human consumption onlyand should never be used as the input to another command.
您不应该ls
在 shell 脚本中使用。的输出ls
是用于人类消费仅不应该被用作输入到另一个命令。
First, the correct solution to your problem.
首先,正确解决您的问题。
#!/bin/bash
data=("$(ls -trh "$@")")
for entry in "${data[@]}"
do
echo "${entry}"
done
This presumes that you don't have any special ordering or name format requirements. You can refer to this answerif you need ordering like ls -t
.
这假定您没有任何特殊的排序或名称格式要求。您可以参考这个答案,如果你需要订购类似ls -t
。
Your problem is common and I call it the "Who sees what?" problem. You say myscript.sh E*
and expect a literal E*
to be passed to your script, but in fact since this argument is unquoted the globwill be expanded by bash
before your script is called, so what your script sees is all files in the current directory whose names started with E
.
你的问题很常见,我称之为“谁看到了什么?” 问题。您说myscript.sh E*
并期望将文字E*
传递给您的脚本,但实际上,由于此参数未加引号,因此在调用脚本之前,glob将被扩展bash
,因此您的脚本看到的是当前目录中名称以E
.
As you note, single-quoting the argument "fixes" this. This is because bash
doesn't perform any special expansion inside single quotes, so now your script sees E*
literally. You have, effectively, escaped the *
so bash
won't expand it before passing it to your script. To do this without using quotes is possible by backslash-escape the *
正如您所注意到的,单引号参数“修复”了这一点。这是因为bash
不会在单引号内执行任何特殊扩展,所以现在您的脚本可以看到E*
字面意思。你已经有效地逃脱了,*
所以在bash
将它传递给你的脚本之前不会扩展它。要做到这一点而不使用引号可以通过反斜杠转义*
myscript.sh E*
But a superior solution is to allow bash
to expand the glob and change your script to handle processing multiple file arguments instead. For example:
但是一个更好的解决方案是允许bash
扩展 glob 并更改您的脚本以处理多个文件参数。例如:
"find-files.sh"
#!/bin/bash
store=
date_given=
inc_files=()
limit=$( date +"%s" -d "$date_given" )
while read -r -d $'./find-files.sh '/a/dir/to/search' '2013-01-12 18:12:09'
' seconds file; do
seconds=${seconds%.*}
if [[ $seconds -le $limit ]]; then
printf "seconds=$seconds, file=$file\n"
#block word splitting
inc_files=( "${inc_files[@]}" "$file" )
#do whatever you want here...
fi
done < <(find $store -maxdepth 1 -type f -name "*.inc*" -printf "%T@ %f##代码##" | sort -zn)
Here I assume that all arguments will be file names. I have changed data
into an array and added quotes to all expansions, to preserve whitespace properly. This solution is still wrong, because it parses ls
output, but now you probably get the behavior you expect out of the unquoted E*
这里我假设所有参数都是文件名。我已更改data
为一个数组并为所有扩展添加了引号,以正确保留空格。此解决方案仍然是错误的,因为它解析ls
输出,但现在您可能会从未引用的内容中获得您期望的行为E*
In general you should alwaysquote the expansion of variables in shell scripts, because that probably does what you expect (and unquoted expansion probably does not!)
通常,您应该始终引用 shell 脚本中变量的扩展名,因为这可能符合您的预期(而未引用的扩展名可能不会!)
回答by centurian
Here's a quick example:
这是一个快速示例:
find files of a directory ordered by their modification dates from older to newer but less than or equal a given date and containing a '.inc' in their names
##代码##查找按修改日期从旧到新但小于或等于给定日期并在其名称中包含“.inc”的目录中的文件
and call it:
并称之为:
##代码##I agree with @Sorpigal https://unix.stackexchange.com/questions/22674/shell-script-for-moving-oldest-files/29205#29205it's very helpful except 'IFS=' in while loop that breaks everything in my system (Ubuntu).
我同意@Sorpigal https://unix.stackexchange.com/questions/22674/shell-script-for-moving-oldest-files/29205#29205它非常有用,除了while循环中的'IFS ='打破了我的一切系统(Ubuntu)。