你好,我在这里学习脚本。我正在尝试使用“for”循环编写一个简单的脚本。
我在一个名为 user 的文件夹中有数百个文件夹。
如果我运行此命令,我会得到一个需要移动到另一个文件夹的文件夹列表
cat failed | awk -F ":" '/FAILED/ {print $1}' | uniq
即任务失败的用户下的文件夹必须移动到 users/failed/failedusers
我目前正在做的是我首先使用创建一个新文件
cat failed | awk -F ":" '/FAILED/ {print $1}' | uniq > failedusers
然后我使用以下命令移动文件夹
while read line; do cp -r users/$line users/failed; done < failedusers
我的问题是我可以只使用为了命令而不是将输出写入另一个文件并使用阅读时命令来完成它?
例如,以某种方式为循环中的变量赋值,例如
faileduser=`cat failed | awk -F ":" '/FAILED/ {print $1}' | uniq`
然后写一些类似的东西
mv users/$faileduser user/failed/$faileduser
当我尝试编写类似上面的内容时,我遇到了各种错误。
谢谢
答案1
使用 GNUxargs
和支持 ksh 样式进程替换的 shell,您可以执行以下操作:
xargs -rd '\n' -I USER -a <(awk -F : '/FAILED/ {print $1}' failed | sort -u
) cp -r users/USER user/failed/USER
有了zsh
,你可以这样做:
faileduser=( ${(f)"$(awk -F : '/FAILED/ {print $1}' failed | sort -u)"} )
autoload zargs
zargs -rI USER -- $faileduser -- cp -r users/USER user/failed/USER
假设你想复制USER
到 user/failed/USER
,即复制它进入 user/failed
,你也可以这样做(仍然使用zsh
):
(( $#faileduser )) && cp -r users/$^faileduser user/failed/
使用bash
shell,您可以执行类似的操作:
readarray -t faileduser < <(awk -F : '/FAILED/ {print $1}' failed | sort -u)
(( ${#faileduser[@]} )) &&
cp -r "${faileduser[@]/#/user\/}" user/failed/
或者在所有用户名前面awk
添加:user/
readarray -t faileduser < <(awk -F : '/FAILED/ {print "user/"$1}' failed | sort -u)
(( ${#faileduser[@]} )) &&
cp -r "${faileduser[@]}" user/failed/
对于for
循环,使用类似 Korn 的 shell(包括bash
, 也可以与 一起使用zsh
),语法将是:
for user in "${faileduser[@]}"; do
cp -r "user/$user" "user/failed/$user"
done
其中zsh
可以缩短为:
for user ($faileduser) cp -r user/$user user/failed/$user
和:
faileduser=`cat failed | awk -F ":" '/FAILED/ {print $1}' | uniq`
(`...`
是命令替换的过时且已弃用的形式。请使用$(...)
)。
您将awk
的输出存储在标量,不是数组变量。
在 中zsh
,您可以使用参数扩展标志将其拆分为换行符f
,就像我们在上面的命令替换中直接执行的操作一样:
array=( ${(f)faileduser} )
在 bash(或 ksh)中,您可以在禁用 glob 并调整 split 后使用 split+glob 运算符:
set -o noglob
IFS=$'\n'
array=( $faileduser )
(是的,在 中bash
,不加引号的参数扩展会调用隐式 split+glob 运算符 (!),这是从 Bourne shell 继承的错误功能,在 zsh 和大多数现代的非 Bourne-like shell 中已修复)。