在从一行(bash)命令创建文件的目标中,目标是输出任何文本文件的内容 - 在本例中为bash脚本 - 并将每行包装在能够输出的命令中粘贴在终端窗口中的同一行。
示例源输入文件:
Line 1
Line 2
Line 3
示例所需输出:
echo 'Line 1';echo 'Line 2';echo 'Line 3';
注意:只要源是人类可读的,用printf
,echo
或其他命令来创建输出都无关紧要。
一个障碍是单引号,不会重新创建。因此,请使用特殊处理的 $'string'形式。单词扩展为字符串,替换为ANSI C标准指定的反斜杠转义字符。
另一个要求是从新文件中的旧文件重新创建制表符。因此希望替换< \ tab> \ t 的字符。
我们尝试使用sed
或tr
执行此操作失败。如何使用escape \ t对应替换制表符,并且仍能输出带有原始引号的行?
输入文件/Library/Scripts/BootRepairMount.sh包含:
$ cat /Library/Scripts/BootRepairMount.sh
#!/bin/bash
sleep 18
for OUTPUT in $(diskutil list | grep ': Apple_HFS' | awk '{ print $NF }')
do
if [[ -z $(df -lnh | grep /dev/$OUTPUT) ]]; then
echo "$OUTPUT is not mounted, repair and mount"
diskutil repairVolume $OUTPUT
diskutil mount $OUTPUT
fi
done
我们可以创建的最佳shell一行命令是:
$ oldifs=$IFS;printf '\n';printf '{';while IFS= read -r p;do [[ "$p" == *"'"* ]] && echo -n "echo $'$p';" || echo -n "echo '$p';"; done < /Library/Scripts/BootRepairMount.sh | tr '\t' '\134\164';printf '}';printf '\n\n';IFS=$oldifs
返回此错误输出:
{echo '#!/bin/bash';echo 'sleep 18';echo $'for OUTPUT in $(diskutil list | grep ': Apple_HFS' | awk '{ print $NF }')';echo 'do';echo '\if [[ -z $(df -lnh | grep /dev/$OUTPUT) ]]; then';echo '\\echo "$OUTPUT is not mounted, repair and mount"';echo '\\diskutil repairVolume $OUTPUT';echo '\\diskutil mount $OUTPUT';echo '\fi';echo 'done';}
所需的输出是:
{echo '#!/bin/bash';echo 'sleep 18';echo $'for OUTPUT in $(diskutil list | grep ': Apple_HFS' | awk '{ print $NF }')';echo 'do';echo '\tif [[ -z $(df -lnh | grep /dev/$OUTPUT) ]]; then';echo '\t\techo "$OUTPUT is not mounted, repair and mount"';echo '\t\tdiskutil repairVolume $OUTPUT';echo '\t\tdiskutil mount $OUTPUT';echo '\tfi';echo 'done';}
$ oldifs=$IFS;printf '\n';printf '{';while IFS= read -r p;do [[ "$p" == *"'"* ]] && printf 'printf $'\''%q'\'';' "$p" || printf 'printf '\''%q'\'';' "$p"; done < /Library/Scripts/BootRepairMount.sh;printf '}';printf '\n\n';IFS=$oldifs
返回重度转义的输出:
{printf '\#\!/bin/bash';printf 'sleep\ 18';printf $'for\ OUTPUT\ in\ \$\(diskutil\ list\ \|\ grep\ \':\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Apple_HFS\'\ \|\ awk\ \'\{\ print\ \$NF\ \}\'\)';printf 'do';printf '$'\tif [[ -z $(df -lnh | grep /dev/$OUTPUT) ]]; then'';printf '$'\t\techo "$OUTPUT is not mounted, repair and mount"'';printf '$'\t\tdiskutil repairVolume $OUTPUT'';printf '$'\t\tdiskutil mount $OUTPUT'';printf '$'\tfi'';printf 'done';}
永远不会在Mac OS X 10.7.5中恢复到原来的值。
printf '\#\!/bin/bash';
输出:
\#\!/bin/bash
以及:
echo -e '\#\!/bin/bash'
输出未转义的值
\#\!/bin/bash
根据{{1}}页面, -e
不是Mac OS X 10.7.5 echo
命令的有效命令开关。
答案 0 :(得分:2)
bash的内置命令printf
具有处理此问题的%q
格式代码:
printf '\n{ '; while IFS= read -r p; do printf "echo %q; " "$p"; done < /Library/Scripts/BootRepairMount.sh; printf '}\n\n'
不幸的是,它并不总是选择易于阅读的引用/转义模式。具体来说,它更倾向于转义单个元字符(例如空格),而不是将它们括在引号中:
{ echo \#\!/bin/bash; echo sleep\ 18; echo for\ OUTPUT\ in\ \$(diskutil\ list\ \|\ grep\ \':\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Apple_HFS\'\ \|\ awk\ \'{\ print\ \$NF\ }\'); echo do; echo $'\tif [[ -z $(df -lnh | grep /dev/$OUTPUT) ]]; then'; echo $'\t\techo "$OUTPUT is not mounted, repair and mount"'; echo $'\t\tdiskutil repairVolume $OUTPUT'; echo $'\t\tdiskutil mount $OUTPUT'; echo $'\tfi'; echo done; }
答案 1 :(得分:1)
如果我理解正确,您需要将一条长行粘贴到Terminal.app并希望获取原始脚本的“源代码”。因此,需要一个脚本来生成单行脚本。
也许有点不寻常的解决方案,但它简单易行。
这里是名为test.sh
的测试脚本(而不是你的BootReapirMount.sh)
for i in {1..10}
do
date
done
这是生成器脚本mkecho.sh
#!/bin/bash
[[ ! -f "$1" ]] && echo "Need filename" && exit 1
asc=$(gzip < "$1" | base64)
echo "base64 -D <<<'$asc'| gzip -d"
现在,运行:
bash mkecho.sh test.sh
你会得到下一个:
base64 -D <<<'H4sIAASwqFEAA0vLL1LIVMjMU6g21NMzNKjlSsnn4kxJLEkFMvJSuQBZFmY0HwAAAA=='| gzip -d
如果您将上述内容复制并粘贴到终端中,它将显示原始test.sh
VARIANT2
如果您想直接执行该脚本,则应将mkecho.sh
修改为下一个mkeval.sh
#!/bin/bash
[[ ! -f "$1" ]] && echo "Need filename" && exit 1
asc=$(gzip < "$1" | base64)
echo -n 'eval "$(base64 -D <<<"'
echo -n $asc
echo -n '" | gzip -d)"'
echo
运行时
bash mkeval.sh test.sh
将获得
eval "$(base64 -D <<<"H4sIAASwqFEAA0vLL1LIVMjMU6g21NMzNKjlSsnn4kxJLEkFMvJSuQBZFmY0HwAAAA==" | gzip -d)"
最后当您将其复制并粘贴到终端时,运行test.sh
并获得:
Fri May 31 16:25:08 CEST 2013
... 8 lined deleted...
Fri May 31 16:25:08 CEST 2013
警告:因为脚本未针对所有可能的条件进行测试,也未针对重定向等进行测试 - 我确实不建议使用eval
版本。
答案 2 :(得分:0)
sed 's/\\t/\\/g'
$ echo 'ffsd \tif [[ -z $' | sed 's/\\t/\\/g'
ffsd \if [[ -z $