linux truncate first line - is there a better method - linux

There is the following which will truncate a file to take the first line and overwrite it,
I wonder if there is a cleaner way then to do this:
touch temp.txt; cat versions.txt | head -1 > temp.txt; mv temp.txt versions.txt
Note that this does not work:
cat versions.txt | head -1 > versions.txt
and the touch is not necessary on most systems

Here's one way of doing it in-place
ex -c ':2,$d' -c ':wq' versions.txt

You could do it with sed in one command:
sed -i -n 1p versions.txt

Use sed like this:
sed -i.bak '1d' file

Ho about this
ONE=`awk 'NR==1 {print;exit}' versions.txt`&& echo $ONE>versions.txt

Related

How to apply my sed command to some lines of all my files?

I've 95 files that looks like :
2019-10-29-18-00/dev/xx;512.00;0.4;/var/x/xx/xxx
2019-10-29-18-00/dev/xx;512.00;0.68;/xx
2019-10-29-18-00/dev/xx;512.00;1.84;/xx/xx/xx
2019-10-29-18-00/dev/xx;512.00;80.08;/opt/xx/x
2019-10-29-18-00/dev/xx;20480.00;83.44;/var/x/x
2019-10-29-18-00/dev/xx;3584.00;840.43;/var/xx/x
2019-10-30-00-00/dev/xx;2048.00;411.59;/
2019-10-30-00-00/dev/xx;7168.00;6168.09;/usr
2019-10-30-00-00/dev/xx;3072.00;1036.1;/var
2019-10-30-00-00/dev/xx;5120.00;348.72;/tmp
2019-10-30-00-00/dev/xx;20480.00;2033.19;/home
2019-10-30-12-00;/dev/xx;5120.00;348.72;/tmp
2019-10-30-12-00;/dev/hd1;20480.00;2037.62;/home
2019-10-30-12-00;/dev/xx;512.00;0.43;/xx
2019-10-30-12-00;/dev/xx;3584.00;794.39;/xx
2019-10-30-12-00;/dev/xx;512.00;0.4;/var/xx/xx/xx
2019-10-30-12-00;/dev/xx;512.00;0.68;/xx
2019-10-30-12-00;/dev/xx;512.00;1.84;/var/xx/xx
2019-10-30-12-00;/dev/xx;512.00;80.08;/opt/xx/x
2019-10-30-12-00;/dev/xx;20480.00;83.44;/var/xx/xx
2019-10-30-12-00;/dev/x;3584.00;840.43;/var/xx/xx
For some lines I've 2019-10-29-18-00/dev and for some other lines, I've 2019-10-30-12-00;/dev/
I want to add the ; before the /dev/ where it is missing, so for that I use this sed command :
sed 's/\/dev/\;\/dev/'
But How I can apply this command for each lines where the ; is missing ? I try this :
for i in $(cat /home/xxx/xxx/xxx/*.txt | grep -e "00/dev/")
do
sed 's/\/dev/\;\/dev/' $i > $i
done
But it doesn't work... Can you help me ?
Could you please try following with GNU awkif you are ok with it.
awk -i inplace '/00\/dev\//{gsub(/00\/dev\//,"/00;/dev/")} 1' *.txt
sed solution: Tested with GNU sed for few files and it worked fine.
sed -i.bak '/00\/dev/s/00\/dev/00\;\/dev/g' *.txt
This might work for you (GNU sed & parallel):
parallel -q sed -i 's#;*/dev#;/dev#' ::: *.txt
or if you prefer:
sed -i 's#;*/dev#;/dev#' *.txt
Ignore lines with ;/dev.
sed '/;\/dev/{p;d}; s^/dev^;/dev^'
The /;\/dev/ check if the line has ;/dev. If it has ;/dev do: p - print the current line and d - start from the beginning.
You can use any character with s command in sed. Also, there is no need in escaping \;, just ;.
How I can apply this command for each lines where the ; is missing ? I try this
Don't edit the same file redirecting to the same file $i > $i. Think about it. How can you re-write and read from the same file at the same time? You can't, the resulting file will be in most cases empty, as the > $i will "execute" first making the file empty, then sed $i will start running and it will read an empty file. Use a temporary file sed ... "$i" > temp.txt; mv temp.txt "$i" or use gnu extension -i sed option to edit in place.
What you want to do really is:
grep -l '00/dev/' /home/xxx/xxx/xxx/*.txt |
xargs -n1 sed -i '/;\/dev/{p;d}; s^/dev^;/dev^'
grep -l prints list of files that match the pattern, then xargs for each single one -n1 of the files executes sed which -i edits files in place.
grep for filtering can be eliminated in your case, we can accomplish the task with a single sed command:
for f in $(cat /home/xxx/xxx/xxx/*.txt)
do
[[ -f "$f" ]] && sed -Ei '/00\/dev/ s/([^;])(\/dev)/\1;\2/' "$f"
done
The easiest way would be to adjust your regex so that it's looking a bit wider than '/dev/', e.g.
sed -i -E 's|([0-9])/dev|\1;/dev|'
(note that I'm taking advantage of sed's flexible approach to delimiters on substitute. Also, -E changes the group syntax)
Alternatively, sed lets you filter which lines it handles:
sed -i '/[0-9]\/dev/ s/\/dev/;/dev/'
This uses the same substitution you already have but only applied on lines that match the filter regex

put output in the next pipe

I want to move the output of the command:
ls -1 /${TMP_DIR}/*0000000221*.dbf | xargs | sed 's/ /,/g'
In the end of a command that come after it, like that:
ls -1 /${TMP_DIR}/*0000000221*.dbf | xargs | sed 's/ /,/g' | impdp sim/sim files=$1
For example:
execute ls -1 /${TMP_DIR}/*0000000221*.dbf | xargs | sed 's/ /,/g' will give me:
/tmp/a_0000000221.dbf,/tmp/a_00000002212.dbf,/tmp/b_0000000221.dbf
So I want the final command will look like:
impdp sim/sim files=/tmp/a_0000000221.dbf,/tmp/a_00000002212.dbf,/tmp/b_0000000221.dbf
EDIT:
Sorry I didnt write this from the beginning - I've variable in the command ${TMP_DIR}
You probably don't need that many pipes. You can use it like this:
printf "impdp sim/sim files=" && printf "%s," /tmp/*0000000221*.dbf
impdp sim/sim files=/tmp/a_0000000221.dbf,/tmp/a_00000002212.dbf,/tmp/b_0000000221.dbf,
ls is a bit redundant if you just want to get the file names.
You can get the shell to glob those and then use printf to put them one per line.
To separate those items with ',' rather than '\n', you can use paste
Finally, putting all that within $() will execute that in a subshell,
and output the result for the command in the current shell.
impdp sim/sim files=$(printf '%s\n' /${TMP_DIR}/*0000000221*.dbf | paste -d, -s)
You can try other order of commands:
impdp sim/sim files=$(ls -1 /tmp/*0000000221*.dbf | xargs | sed 's/ /,/g')
You can use globbing, an array and IFS to construct the parameter string:
$ ls -1
1.txt
2.txt
3.txt
$ echo impdp sim/sim files="$(a=(*.txt);IFS=',';echo "${a[*]}")"
impdp sim/sim files=1.txt,2.txt,3.txt
Obviously this will break on filenames with spaces or newlines.
To run, just remove the echo.
(all solutions including mine assumes your filenames do not contain spaces)
sed is a little overkill, you can use tr and avoid xargs too:
impdp sim/sim files=$(ls /tmp/*0000000221*.dbf | tr "\n" ",")

Redirecting and writing in the same file

Hi i have a script which replaces the certain occurrences in the .sql files and after that writes it in the some new file.So,i m here unnecessarily creating extra files.Is there anyway by which i can write in the same file.
Below is the part of the script:
sed "s/v1/$value1/g" Save.sql >> CreateViewFinal1.sql
sed "s/v2/$value2/g" CreateViewFinal1.sql >> CreateViewFinal2.sql
sed "s/v3/$value3/g" CreateViewFinal2.sql >> CreateViewFinal3.sql
sed "s/v4/$value4/g" CreateViewFinal3.sql >> CreateViewFinal4.sql
sed "s/v5/$value5/g" CreateViewFinal4.sql >> CreateViewFinal5.sql
sed "s/v6/$value6/g" CreateViewFinal5.sql >> CreateViewFinal6.sql
sed "s/v7/$value7/g" CreateViewFinal6.sql >> CreateViewFinal7.sql
sed "s/v8/$value8/g" CreateViewFinal7.sql >> CreateViewFinal8.sql
sed "s/v9/$value9/g" CreateViewFinal8.sql >> CreateViewFinal9.sql
sed "s/a1/$value10/g" CreateViewFinal9.sql >> CreateViewFinal10.sql
sed "s/b1/$value11/g" CreateViewFinal10.sql >> CreateViewFinal11.sql
sed "s/c1/$value12/g" CreateViewFinal11.sql >> CreateViewFinal12.sql
sqlplus -S -L cimkroger/cimkroger#orcl #CreateViewFinal12.sql
Thanks in advance.
You can sed's inline editing and can avoid multiple sed commands with -e switch like this:
sed -i.bak -e "s/v1/$value1/g" -e "s/v2/$value2/g" -e "s/v3/$value3/g" Save.sql
Yes.
You can change a file directly with the -i option of sed.
Hence, sed -i .... file will replace something in the same file.
Moreover, instead of so many sed different lines, you can do multiple sed actions with the -e option. So instead of:
sed "s/v1/$value1/g" Save.sql >> CreateViewFinal1.sql
sed "s/v2/$value2/g" CreateViewFinal1.sql >> CreateViewFinal2.sql
sed "s/v3/$value3/g" CreateViewFinal2.sql >> CreateViewFinal3.sql
You can do
sed -i -e "s/v1/$value1/g" -e "s/v2/$value2/g" -e "s/v3/$value3/g" Save.sql
and so on.
Example
$ cat file
hello you
$ sed -i -e 's/hello/bye/g' -e 's/you/me/g' file
$ cat file
bye me

How to filter data out of tabulated stdout stream in Bash?

Here's what output looks like, basically:
? RESTRequestParamObj.cpp
? plugins/dupfields2/_DupFields.cpp
? plugins/dupfields2/_DupFields.h
I need to get the filenames from second column and pass them to rm. There's AWK script that goes like awk '{print $2}' but I was wondering if there's another solution.
If you have spaces between the ? and the filename then:
cut -c9-
If they're tabs then:
cut -f2
Placed your output in file
$> cat ./text
? RESTRequestParamObj.cpp
? plugins/dupfields2/_DupFields.cpp
? plugins/dupfields2/_DupFields.h
Edit it with sed
$> cat ./text | sed -r -e 's/(\?[\ \t]*)(.*)/\2/g'
RESTRequestParamObj.cpp
plugins/dupfields2/_DupFields.cpp
plugins/dupfields2/_DupFields.h
Sed in here is matching 2 parts of line -
? with tabs or spaces
Other characters until the end f the line
And then it changes whole line only with second part.
This might work for you:
echo "? RESTRequestParamObj.cpp" | sed -e 's/^\S\+/rm /' | sh
or using GNU sed
echo "? RESTRequestParamObj.cpp"| sed -r 's/^\S+/rm /e'
bash only solution, assuming your output comes from stdin:
while read line; do echo ${line##* }; done
use cut/perl instead
cut -f2 -t'\t'|xargs rm -rf
<your output>|perl -ne '#cols = split /\t/; print $cols[1]'|xargs rm -rf

how i can add Add text at the beginning of each line?

how i can add Add text at the beginning of each line?
for example:- i have file contain:-
/var/lib/svn/repos/b1me/products/payone/generic/code/core
/var/lib/svn/repos/b1me/products/payone/generic/code/fees
/var/lib/svn/repos/b1me/products/payone/generic/code/2ds
i want it to become:-
svn+ssh://svn.xxx.com.jo/var/lib/svn/repos/b1me/products/payone/generic/code/core
svn+ssh://svn.xxx.com.jo/var/lib/svn/repos/b1me/products/payone/generic/code/fees
svn+ssh://svn.xxx.com.jo/var/lib/svn/repos/b1me/products/payone/generic/code/2ds
in other word i want to add "svn+ssh://svn.xxx.com.jo" at the beginning of each line of this file
One way to do this is to use awk.
awk '{ printf "svn+ssh://svn.xxx.com.jo"; print }' <filename>
If you want to modify the file in place, you can use sed with the -i switch.
sed -i -e 's_.*_svn+ssh://svn.xxx.com.jo&_' <filename>
Using sed:
printf "line1\nline2\n" | sed "s/^/new text /"
Using ex:
printf "line1\nline2\n" | ex -s +"%s/^/foo bar /e" +%p -cq! /dev/stdin
Using vim:
printf "line1\nline2\n" | vim - -es +"%s/^/foo bar /e" +%p -cq!
Using shell:
printf "line1\nline2\n" | while read line; do echo foo bar $line; done
ruby -pne 'sub(/^/,"svn+ssh://svn.xxx.com.jo")' file
Simple way:
sed -i 's_._svn+ssh://svn.xxx.com.jo_' <filename>
It can also be done with Perl:
perl -pe 's#^#svn+ssh://svn.xxx.com.jo#' input.file

Resources