linux bash xargs for循环有变量和参数问题

rqqzpn5f  于 2023-03-22  发布在  Linux
关注(0)|答案(2)|浏览(207)

我有一个while循环,它调用xargs根据部分输出命名文件。

do
$CLIPATH/show attributes attr=0x1006e attr=0x3b1090d attr=0x3b10944 attr=0x3b1093e attr=0x3b10943 attr=0x100c5 attr=0x100ad mh=${line} > /mnt/path/temp
cat /mnt/path/file2 | grep 'x1006e' | awk '{print $3}' | xargs -d $'\n' sh -c 'for arg do [[ -d /mnt/path"$arg" ]] || mkdir /mnt/path/"$arg"; cp /mnt/path/temp /mnt/path/"$arg"/$(eval "date +"%Y-%m-%d_%H_"")"$arg".txt; cat /mnt/path/"$arg"/$(eval "date +"%Y-%m-%d_%H_"")"$arg".txt | grep '0x1006e' | awk '{ s = ""; for (i = 3; i <= NF; i++) s = s $i " "; print s }' > /mnt/path/"$arg"/$(eval "date +"%Y-%m-%d_%H_"")"$arg"_name.txt ; done' _
done

我有三个问题:
第一个是最后一个awk部分 *;cat /mnt/path/"$arg”/$(eval“date +"%Y-%m-%d_%H_””)"$arg”.txt|grep '0x1006e'|**awk '{ s =“";对于(i = 3;i〈= NF; i++)s = s $i““*失败了,因为我认为它需要在xargs循环中进行不同的格式化才能正常运行。
第二个问题是,我似乎不能在没有错误的情况下调用for循环之外的变量。例如,
/mnt/path/
在脚本的前面有一个变量,但它没有被调用,所以我每次都只写完整的路径。
第三个问题是,我无法格式化for循环中的分隔参数,使其看起来很干净,而不出现回车错误。我希望它看起来像这样:

do
$CLIPATH/show attributes attr=0x1006e attr=0x3b1090d attr=0x3b10944 attr=0x3b1093e attr=0x3b10943 attr=0x100c5 attr=0x100ad mh=${line} > /mnt/path/temp
cat /mnt/path/file2 | grep 'x1006e' | awk '{print $3}' | xargs -d $'\n' sh -c 'for arg do [[ -d /mnt/path"$arg" ]] || mkdir /mnt/path/"$arg";

cp /mnt/path/temp /mnt/path/"$arg"/$(eval "date +"%Y-%m-%d_%H_"")"$arg".txt;

cat /mnt/path/"$arg"/$(eval "date +"%Y-%m-%d_%H_"")"$arg".txt | grep '0x1006e' | awk '{ s = ""; for (i = 3; i <= NF; i++) s = s $i " "; print s }' > /mnt/path/"$arg"/$(eval "date +"%Y-%m-%d_%H_"")"$arg"_name.txt;
done' _
done

我不是最好的编剧,所以我想很多东西都可以写得更好。谢谢你的帮助。

3pvhb19x

3pvhb19x1#

不要把超长代码放在一行中。将代码封装在函数中,使用export -fexportdeclare -fdeclare -p将函数和变量转移到单独的shell中。编写 clear 代码。使用shellcheck检查脚本。不要使用eval。
在这种情况下,只需编写一个普通的循环。

cat /mnt/path/file2 |
grep 'x1006e' |
awk '{print $3}' |
while IFS= read -r arg; do
     mkdir -p /mnt/path/"$arg"
     cp /mnt/path/temp "/mnt/path/$arg/$(date +%Y-%m-%d_%H_)$arg".txt
     cat "/mnt/path/$arg/$(date +%Y-%m-%d_%H_)$arg.txt" |
        grep '0x1006e' |
        awk '{
            s = ""
            for (i = 3; i <= NF; i++) s = s $i " "
            print s
        }' > "/mnt/path/$arg/$(date +%Y-%m-%d_%H_)$arg_name.txt";
done
vjrehmav

vjrehmav2#

这里不需要使用xargs;你正在使用shell运行xargs来传递一堆(子目录)名称到 * 另一个 * shell,然后单独处理它们,而你可以让原始的shell处理它们,这样会更清晰(甚至效率更高)。另外,当使用awk时,您不需要grepcat,这里没有列出的例外情况很少。你只能把bash命令放在do... done中,如果它们是你没有也没有要求的循环体。

dir=/mnt/path # demonstrate this also since you asked about it
now=$(date +"%Y-%m-%d_%H_) # put this in a variable to allow reuse
$CLIPATH/show attributes attr=0x1006e attr=0x3b1090d attr=0x3b10944 attr=0x3b1093e attr=0x3b10943 attr=0x100c5 attr=0x100ad mh=${line} > "$dir"/temp
awk <"$dir"/file2 '/x1006e/{print $3}' | while read -r arg; do
  [[ -d "$dir$arg" ]] || mkdir "$dir$arg"
  cp "$dir/temp" "$dir/$arg/$now$arg".txt
  awk <"$dir/$arg/$now$arg".txt '/0x1006e/{ s = ""; for (i = 3; i <= NF; i++) s = s $i " "; print s }' >"$dir/$arg/$now$arg"_name.txt
done

注:

  • 你真的想把$CLIPATH/show的输出放到$dir/temp中,然后处理$dir/file2中的“arg”值(子目录名)吗?或者它们应该是相同的吗?
  • 通常,如果变量值可以包含空格或“模式(又名通配符或glob)字符?*[,您需要将对它的任何引用括在双引号"...$var..."中以避免问题。在您的情况下,dir=/mnt/path不包含任何此类字符,因此我并不真正需要",但我使用它们来遵循良好的实践。此外,在这里不适用的两个特定地方(赋值和这里的字符串),不需要将$var放在"中,但许多人仍然这样做以保持一致性。
  • 你可以使用下面的技巧,而不是在awk中的3..NF上循环:
awk <input '/0x1006e/{$1=$2=""; print substr($0,3)}' >output

但是如果你这样做,任何阅读或维护你的代码的人都可能用钝器攻击你。

相关问题