cat file.txt | while read in; do chmod 755 "$in"; done
是否有一种更加优雅、更安全的方法?
由于shell(和/或bash)的主要用途是运行其他命令,所以不止一个答案!!
0. Shell命令行扩展
1. xargs
专用工具
2. while read
带有一些备注
3. while read -u
使用专用的fd
,用于交互式处理(示例)
5. 使用内联生成的脚本运行shell
关于OP的请求:在文件中列出的所有目标上运行chmod
,xargs
是指定的工具。但对于其他应用程序、少量文件等等...
如果
你可以使用shell命令行扩展。简单来说:
chmod 755 $(<file.txt)
xargs chmod 755 <file.txt
可以在find命令的找到的文件后面使用pipe
。
find /some/path -type f -uid 1234 -print | xargs chmod 755
file.txt
文件中有特殊字符和/或很多行。xargs -0 chmod 755 < <(tr \\n \\0 <file.txt)
find /some/path -type f -uid 1234 -print0 | xargs -0 chmod 755
xargs -0 -n 1 chmod 755 < <(tr \\n \\0 <file.txt)
chmod
可以接受多个文件作为参数,但这与问题的标题相匹配。xargs
生成的命令中定义文件参数的位置。xargs -0 -I '{}' -n 1 myWrapper -arg1 -file='{}' wrapCmd < <(tr \\n \\0 <file.txt)
seq 1 5
作为输入进行测试试试这个:
xargs -n 1 -I{} echo Blah {} blabla {}.. < <(seq 1 5)
Blah 1 blabla 1..
Blah 2 blabla 2..
Blah 3 blabla 3..
Blah 4 blabla 4..
Blah 5 blabla 5..
每行执行一次您的命令。
在shell下进行循环通常是一个坏主意!有很多关于在shell下进行循环的警告!
在进行循环之前,请考虑并行化和专用工具!
您可以使用bash与和管理专用工具进行交互。一些示例:
for
和while
循环比较第一个脚本(编辑于2023年7月23日!)和第二个脚本,在我的Swap usage by process脚本中。while read
和其它变体。为此,请确保文件以换行符结尾。
如OP所建议,
cat file.txt |
while read in; do
chmod 755 "$in"
done
while read in; do
chmod 755 "$in"
done < file.txt
$IFS
和read
标志的警告:help read
read: read [-r] ... [-d delim] ... [name ...]
...
Reads a single line from the standard input... The line is split
into fields as with word splitting, and the first word is assigned
to the first NAME, the second word to the second NAME, and so on...
Only the characters found in $IFS are recognized as word delimiters.
...
Options:
...
-d delim continue until the first character of DELIM is read,
rather than newline
...
-r do not allow backslashes to escape any characters
...
Exit Status:
The return code is zero, unless end-of-file is encountered...
在某些情况下,你可能需要使用while IFS= read -r in;do
chmod 755 "$in"
done <file.txt
while LANG=C IFS= read -r in ; do
chmod 755 "$in"
done <file.txt
你可以通过以下方式来查看它们:
ls -l /dev/fd/
或者
ls -l /proc/$$/fd/
while read <&7 filename; do
ans=
while [ -z "$ans" ]; do
read -p "Process file '$filename' (y/n)? " foo
[ "$foo" ] && [ -z "${foo#[yn]}" ] && ans=$foo || echo '??'
done
if [ "$ans" = "y" ]; then
echo Yes
echo "Processing '$filename'."
else
echo No
fi
done 7<file.txt
exec 7<file.txt # Without spaces between `7` and `<`!
# ls -l /dev/fd/
read <&7 headLine
while read <&7 filename; do
case "$filename" in
*'----' ) break ;; # break loop when line end with four dashes.
esac
....
done
read <&7 lastLine
exec 7<&- # This will close file descriptor 7.
# ls -l /dev/fd/
fd
并存储到一个变量中:exec {varname}</path/to/input
。while read -ru ${fle} filename;do
ans=
while [ -z "$ans" ]; do
read -rp "Process file '$filename' (y/n)? " -sn 1 foo
[ "$foo" ] && [ -z "${foo/[yn]}" ] && ans=$foo || echo '??'
done
if [ "$ans" = "y" ]; then
echo Yes
echo "Processing '$filename'."
else
echo No
fi
done {fle}<file.txt
或者
exec {fle}<file.txt
# ls -l /dev/fd/
read -ru ${fle} headline
while read -ru ${fle} filename;do
[[ -n "$filename" ]] && [[ -z ${filename//*----} ]] && break
....
done
read -ru ${fle} lastLine
exec {fle}<&-
# ls -l /dev/fd/
sed <file.txt 's/.*/chmod 755 "&"/' | sh
sed <file.txt 's/.*/if [ -e "&" ];then chmod 755 "&";fi/' | sh
sed 's/.*/[ -f "&" ] \&\& echo "Processing: \\"&\\"" \&\& chmod 755 "&"/' \
file.txt | sh
rsync
日志输出作为sed
输入,以便在删除对应的描述文件时删除项目文件。请参见我的回答,如果在另一个目录中不存在同名但扩展名不同的文件,则删除文件,这与SO提问者的预期有很大不同。是的。
while read in; do chmod 755 "$in"; done < file.txt
这种方法可以避免使用 cat
命令。
cat
命令几乎总是不适合此类用途。您可以阅读有关“无用的Cat使用”的更多信息。
cat
是一个好主意,但在这种情况下,所指的命令是xargs
。 - F. Hauri - Give Up GitHubchmod
的事情时(例如,对文件中的每一行运行一个命令)。 - Per Lundbergread -r
从标准输入读取单行(没有-r
的read
会解释反斜杠,你不想要那个)。” - That Brazilian Guy如果你有一个好的选择器(例如目录中所有的 .txt 文件),你可以这样做:
for i in *.txt; do chmod 755 "$i"; done
或者您自己的变体:
while read line; do chmod 755 "$line"; done < file.txt
export
。它的作用是使变量对子进程可见(因此,如果您想在从当前进程启动的子shell中更改分隔符,则很有用,但在这里并不真正相关或有用)。 - tripleee如果你希望针对每一行并行运行命令,你可以使用GNU Parallel
parallel -a <your file> <program>
您的文件中的每一行将作为程序的参数传递。默认情况下,parallel
将运行与您的 CPU 核心数相同的线程。但您可以使用 -j
参数来指定线程数量。
如果您知道输入中没有任何空格:
xargs chmod 755 < file.txt
如果路径中可能含有空格,并且您使用GNU xargs,请使用以下命令:tr '\n' '\0' < file.txt | xargs -0 chmod 755
xargs
是非常强大的工具。这个工具非常古老,它的代码已经被重新审查过了。它的目标最初是为了在遵守 shell 限制(64kchar/line 或者其他)的情况下构建行。现在这个工具可以处理非常大的文件,并且可以大大减少到最终命令的 fork 数量。请参考我的回答和/或 man xargs
。 - F. Hauri - Give Up GitHubbrew install findutils
)在macOS上安装GNU xargs,然后用gxargs
代替GNU xargs,例如:gxargs chmod 755 < file.txt
。 - Jasexargs
本身很强大,但您必须了解它如何处理(或无法处理)输入中的引号等内容。使用 xargs -0
的解决方法完全可预测和强大,但遗憾的是仅适用于 GNU xargs
。 - tripleee现在(在GNU Linux中),xargs
仍然是解决这个问题的答案,但是…现在你可以使用-a
选项直接从文件中读取输入:
xargs -a file.txt -n 1 -I {} chmod 775 {}
xargs -a
是GNU扩展的一部分,这意味着它通常可以在Linux上直接使用,但在其他地方可能需要单独安装许多常见实用程序的GNU版本。从标准输入读取文件名的标准解决方案仍然可以在GNU和其他版本的xargs
中可移植地使用。 - tripleeeawk '{ print "chmod 755 "$0"" | "/bin/sh"}' file.txt
如果你的文件有像这样的字段分隔符:
field1,field2,field3
要仅获取第一个字段,可以执行以下操作:
awk -F, '{ print "chmod 755 "$1"" | "/bin/sh"}' file.txt
我看到您标记了bash,但Perl也是实现此操作的好方法:
perl -p -e '`chmod 755 $_`' file.txt
您还可以应用正则表达式来确保您获取正确的文件,例如仅处理 .txt 文件:
perl -p -e 'if(/\.txt$/) `chmod 755 $_`' file.txt
为了“预览”正在发生的事情,只需用双引号替换反引号,并在前面加上print
:
perl -p -e 'if(/\.txt$/) print "chmod 755 $_"' file.txt
perl -lpe 'chmod 0755, $_' file.txt
命令——使用 -l
来启用“自动去除换行符”功能。 - glenn jackman这个逻辑也适用于许多其他目标。 如何从/home/文件系统中读取每个用户的.sh_history?如果有成千上万个用户怎么办?
#!/bin/ksh
last |head -10|awk '{print $1}'|
while IFS= read -r line
do
su - "$line" -c 'tail .sh_history'
done
xargs
最初就是为了满足这种需求而构建的,所以它具有一些特性,比如在当前环境下尽可能长地构建命令来调用chmod
,以减少执行次数并降低forks以确保效率。使用while ;do..done <$file
会为每个文件运行1个fork,而xargs
可以以可靠的方式为数千个文件运行1个fork...。 - F. Hauri - Give Up GitHubcat file.txt | tr \\n \\0 | xargs -0 -n1 chmod 755
- F. Hauri - Give Up GitHub