我有一些文字在所有行上都有一些前导空格。我想从最短的行中删除空格(如果它更简单,可以将此要求更改为第一行),然后从所有其他行中删除相同数量的空格。
E.g。我有这样的文字:
var flatten = function(result, next_array) {
console.log('current result', result);
return result.concat(next_array);
};
[1, [2], [3, 4]]
.reduce(flatten, []);
我希望得到这样的文字:
var flatten = function(result, next_array) {
console.log('current result', result);
return result.concat(next_array);
};
[1, [2], [3, 4]]
.reduce(flatten, []);
基本上,我想将文本移到最左边,直到左边至少有一行没有空格,并保留所有其他行上的所有其他前导空格。
用例就是从代码段的中间复制代码以粘贴为其他地方的示例。我目前所做的是复制代码,使用paste insert mode粘贴到vim,使用<<
直到我得到所需的输出,然后复制缓冲区。可以在TextMate中使用 Cmd - [。
我想要的是使用shell脚本执行此操作,以便我可以使用热键触发它以获取剪贴板内容,删除所需的空格并粘贴结果。
答案 0 :(得分:4)
这个awk单行也可以为你做。它假设您要删除至少1个空格。 (因为我在你的例子中看到,有一条空行,没有任何前导空格,但无论如何所有行都向左移动。)
用你的例子测试:
kent$ cat f
var flatten = function(result, next_array) {
console.log('current result', result);
return result.concat(next_array);
};
[1, [2], [3, 4]]
.reduce(flatten, []);
kent$ awk -F '\\S.*' '{l=length($1);if(l>0){if(NR==1)s=l; else s=s>l?l:s;}a[NR]=$0}END{for(i=1;i<=NR;i++){sub("^ {"s"}","",a[i]);print a[i]}}' f
var flatten = function(result, next_array) {
console.log('current result', result);
return result.concat(next_array);
};
[1, [2], [3, 4]]
.reduce(flatten, []);
修改强>
我不认为awk脚本不可读。但你必须知道awk脚本的语法。无论如何,我正在补充一些解释:
awk脚本有两个块,第一个块是在读取文件的每一行时执行的。在读取文件的最后一行后执行END
块。请参阅下面的公司以获得解释。
awk -F '\\S.*' #using a delimiter '\\S.*'(regex). the first non-empty char till the end of line
#so that each line was separated into two fields,
#the field1: leading spaces
#and the field2: the rest texts
'{ #block 1
l=length($1); #get the length of field1($1), which is the leading spaces, save to l
if(l>0){ #if l >0
if(NR==1)s=l; #NR is the line number, if it was the first line, s was not set yet, then let s=l
else s=s>l?l:s;} #else if l<s, let s=l otherwise keep s value
a[NR]=$0 #after reading each line, save the line in a array with lineNo. as index
} #this block is just for get the number of "shortest" leading spaces, in s
END{for(i=1;i<=NR;i++){ #loop from lineNo 1-last from the array a
sub("^ {"s"}","",a[i]); #replace s number of leading spaces with empty
print a[i]} #print the array element (after replacement)
}' file #file is the input file
答案 1 :(得分:2)
可以在.bash_profile
中定义这些函数,以便在任何地方访问它们,而不是创建脚本文件。它们不需要第一行匹配:
shiftleft(){
len=$(grep -e "^[[:space:]]*$" -v $1 | sed -E 's/([^ ]).*/x/' | sort -r | head -1 | wc -c)
cut -c $(($len-1))- $1
}
用法:shiftleft myfile.txt
这适用于某个文件,但必须进行修改才能使用pbpaste
管道传输给它...
注意:绝对受到@JoSo答案的启发,但修复了那里的错误。 (使用sort -r
和cut -c N-
并且在len上缺少$并且不会被没有空格的空行挂断。)
编辑:在OSX上使用剪贴板内容的版本:
shiftclip(){
len=$(pbpaste | grep -e "^[[:space:]]*$" -v | sed -E 's/([^ ]).*/x/' | sort -r | head -1 | wc -c)
pbpaste | cut -c $(($len-1))-
}
此版本的用法:
复制感兴趣的文本,然后键入shiftclip
。要将输出直接复制回剪贴板,请执行shiftclip | pbcopy
答案 2 :(得分:1)
len=$(sed 's/[^ ].*//' <"$file"| sort | head -n1 | wc -c)
cut -c "$((len))"- <"$file"
或者,可读性稍差但避免了排序的开销:
len=$(awk 'BEGIN{m=-1} {sub("[^ ].*", "", $0); l = length($0); m = (m==-1||l<m) ? l : m; } END { print m+1 }' <"$file")
cut -c "$((len))"- <"$file"
答案 3 :(得分:0)
嗯...这不是很漂亮,也假设您可以访问Bash,但是如果你能接受你的“第一线”规则:
#!/bin/bash
file=$1
spaces=`head -1 $file | sed -re 's/(^[ ]+)(.+)/\1/g'`
cat $file | sed -re "s/^$spaces//"
它也只假设空格字符(即你需要调整标签),但你明白了。
假设您的示例位于文件snippet.txt
中,请将bash代码放入脚本(例如“shiftleft”),“chmod + x”脚本中,然后运行:
shiftleft snippet.txt