2ma*_*mac 4 command-line bash wildcards touch mkdir
假设我有一个目录/,它包含许多目录/mydir、/hisdir、/herdir,并且每个目录都需要具有相似的结构。
对于 中的每个目录/,都需要一个目录doc和一个文件doc1.txt。
人们可能天真地认为他们可以执行
mkdir */doc
touch */doc/doc1.txt
Run Code Online (Sandbox Code Playgroud)
但它们是错误的,因为通配符不是这样工作的。
有没有办法做到这一点,而无需在示例中制作一次结构然后将cp其传递给其他人?
而且,如果没有,有没有办法在不覆盖任何现有文件的情况下执行上述解决方法(假设mydir已经包含具有我想保留的一些数据的结构)?
编辑:如果可能,我也想避免使用脚本。
在 bash 中,使用类似这些行的内容:
mkdir -p {mydir,hisdir,herdir}/doc
touch {mydir,hisdir,herdir}/doc/doc1.txt
Run Code Online (Sandbox Code Playgroud)
该{...}语法称为“大括号扩展”,与文件名必须存在的路径名扩展不同,生成的结果不需要匹配任何已经存在的内容。这-p意味着根据需要创建路径的所有嵌套组件——否则,当 mkdir 尝试在父目录之前创建最终的“doc”目录时,您将收到错误。
(查看 bash 手册页中的示例;像这样创建子目录正是常见用例。)
如果 mydir、hisdor 和 herdir 已经存在并且您不想重新输入它们,Stéphane Chazelas 的解决方案可能是最聪明的,但除非您一直这样做,否则聪明并不总是最好的——我永远不会记得bash 数组扩展的东西,我敢打赌,许多初级系统管理员都不会认出它。在这种情况下,我想我会推荐一个循环或find,像这样:
find . -maxdepth 1 -mindepth 1 -type d \
-execdir mkdir {}/doc \; -execdir touch {}/doc/doc1.txt \;
Run Code Online (Sandbox Code Playgroud)
但是,实际上,简单循环的优点是直截了当——而且打字不多!
zsh:dirs=(*(/))
mkdir -- $^dirs/doc
touch -- $^dirs/doc/doc1.txt
Run Code Online (Sandbox Code Playgroud)
(/)是一个通配符,/意味着只选择目录。
$^array(让人想起rc的^运算符)是在数组上打开类似花括号的扩展类型,$^array/doc就像{elt1,elt2,elt3}/doc(其中elt1, elt2,elt3是数组的元素)。
还可以这样做:
mkdir -- *(/e:REPLY+=/doc:)
touch -- */doc(/e:REPLY+=/doc1.txt:)
Run Code Online (Sandbox Code Playgroud)
Where e is another globbing qualifier that executes some given code on the file to select.
rc/es/akanga:dirs = */
mkdir -- $dirs^doc
touch -- $dirs^doc/doc1.txt
Run Code Online (Sandbox Code Playgroud)
That's using the ^ operator which is like an enhanced concatenation operator.
rc doesn't support globbing qualifiers (which is a zsh-only feature). */ expands to all the directories and symlinks to directories, with / appended.
tcsh:set dirs = */
mkdir -- $dirs:gs:/:/doc::q
touch -- $dirs:gs:/:/doc/doc1.txt::q
Run Code Online (Sandbox Code Playgroud)
The :x are history modifiers that can also be applied to variable expansions. :gs is for global substitute. :q quotes the words to avoid problems with some characters.
zsh or bash:dirs=(*/)
mkdir -- "${dirs[@]/%/doc}"
touch -- "${dirs[@]/%/doc/doc1.txt}"
Run Code Online (Sandbox Code Playgroud)
${var/pattern/replace} is the substitute operator in Korn-like shells. With ${array[@]/pattern/replace}, it's applied to each element of the array. % there means at the end.
dirs=(*/) includes directories and symlinks to directories (and there's no way to exclude symlinks other than using [ -L "$file" ] in a loop), while dir=(*(/)) (zsh extension) only includes directories (dir=(*(-/)) to include symlinks to directories without adding the trailing slash).
They exclude hidden dirs. Each shell has specific option to include hidden files).
If the current directory is writable by others, you potentially have security problems. As one could create a symlink there to cause you to create dirs or files where you would not want to. Even with solutions that don't consider symlinks, there's still a race condition as one may be able to replace a directory with a symlink in between the dirs=(*/) and the mkdir....
| 归档时间: |
|
| 查看次数: |
1306 次 |
| 最近记录: |