How can I remove the characters or text to show only the PID in terminal. Ubuntu/Linux terminal - sed

How can I remove the characters/texts from this output?
I've been trying to sed/cut but I cant really do it.
My command:
xprop -id $(xprop -root 32x '\t$0' _NET_ACTIVE_WINDOW | cut -f 2) _NET_WM_PID
Output:
_NET_WM_PID(CARDINAL) = 3239
Expected output:
3239

You can do this using cut alone. Note that the cut command has the argument -d which defaults to tab but you can pass other delimiter.
xprop -id $(xprop -root _NET_ACTIVE_WINDOW | cut -d\# -f2) _NET_WM_PID | cut -d\ -f3
Lets break this down into its parts, and start at the inside.
xprop -root _NET_ACTIVE_WINDOW | cut -d\# -f2 select the id, by using the pound symbol as delimiter for cut, the first field is everything before the # and the second field is everything behind the first #, here it is the id
$( ... ) is replaced by the result of the command inside the parens, here that is the id
xprop -id $( ... ) _NET_WM_PID | cut -d\ -f3 the outer xprop result can be cutted at the space, which give use three fields:
_NET_WM_PID(CARDINAL)
=
the value (without leading space as one would get by using = as delimiter)
Note that we use -d\ to specify "space as delimiter", we need to escape the space with a backslash.

sed -E 's#.*/([0-9]*).*#\1#g' file.txt

Related

Regex: how to match up to a character or the end of a line?

I am trying to separate out parts of a path as follows. My input path takes the following possible forms:
bucket
bucket/dir1
bucket/dir1/dir2
bucket/dir1/dir2/dir3
...
I want to separate the first part of the path (bucket) from the rest of the string if present (dir1/dir2/dir3/...), and store both in separate variables.
The following gives me something close to what I want:
❯ BUCKET=$(echo "bucket/dir1/dir2" | sed 's#\(^[^\/]*\)[\/]\(.*\)#\1#')
❯ EXTENS=$(echo "bucket/dir1/dir2" | sed 's#\(^[^\/]*\)[\/]\(.*\)#\2#')
echo $BUCKET $EXTENS
❯ bucket dir1/dir2
HOWEVER, it fails if I only have bucket as input (without a slash):
❯ BUCKET=$(echo "bucket" | sed 's#\(^[^\/]*\)[\/]\(.*\)#\1#')
❯ EXTENS=$(echo "bucket" | sed 's#\(^[^\/]*\)[\/]\(.*\)#\2#')
echo $BUCKET $EXTENS
❯ bucket bucket
... because, in the absence of the first '/', no capture happens, so no substitution takes place. When the input is just 'bucket' I would like $EXTENS to be set to the empty string "".
Thanks!
For something so simple you could use bash built-in instead of launching sed:
$ path="bucket/dir1/dir2"
$ bucket="${path%%/*}"
$ extens="${path#$bucket}"
$ printf '|%s|%s|\n' "$bucket" "$extens"
|bucket|/dir1/dir2|
$ path="bucket"
$ bucket="${path%%/*}"
$ extens="${path#$bucket}"
$ printf '|%s|%s|\n' "$bucket" "$extens"
|bucket||
But if you really want to use sed and capture groups:
$ declare -a bucket_extens
$ mapfile -td '' bucket_extens < <(printf '%s' "bucket/dir1/dir2" | sed -E 's!([^/]*)(.*)!\1\x00\2!')
$ printf '|%s|%s|\n' "${bucket_extens[#]}"
|bucket|/dir1/dir2|
$ mapfile -td '' bucket_extens < <(printf '%s' "bucket" | sed -E 's!([^/]*)(.*)!\1\x00\2!')
$ printf '|%s|%s|\n' "${bucket_extens[#]}"
|bucket||
We use the extended regex (-E) to simplify a bit, and ! as separator of the substitute command. The first capture group is simply anything not containing a slash and the second is everything else, including nothing if there's nothing else.
In the replacement string we separate the two capture groups with a NUL character (\x00). We then use mapfile to assign the result to bash array bucket_extens.
The NUL trick is a way to deal with file names containing spaces, newlines... NUL is the only character that cannot be part of a file name. The -d '' option of mapfile indicates that the lines to map are separated by NUL instead of the default newline.
Don't capture anything. Instead, just match what you don't want and replace it with nothing:
BUCKET=$(echo "bucket" | sed 's#/.*##'). # bucket
BUCKET=$(echo "bucket/dir1/dir2" | sed 's#/.*##') # bucket
EXTENS=$(echo "bucket" | sed 's#[^/]*##') # blank
EXTENS=$(echo "bucket/dir1/dir2" | sed 's#[^/]*##') # /dir1/dir2
As you are putting a slash in the regex. the string with no slashes will not
match. Let's make the slash optional as /\?. (A backslash before ?
is requires due to the sed BRE.) Then would you please try:
#!/bin/bash
#path="bucket/dir1/dir2"
path="bucket"
bucket=$(echo "$path" | sed 's#\(^[^/]*\)/\?\(.*\)#\1#')
extens=$(echo "$path" | sed 's#\(^[^/]*\)/\?\(.*\)#\2#')
echo "$bucket" "$extens"
You don't need to prepend a backslash to a slash.
By convention, it is recommended to use lower cases for user variables.

Remove everything in a line before comma

I have multiple files with lines like:
foo, 123456
bar, 654321
baz, 098765
I would like to remove everything on each line before (and including) the comma.
The output would be:
123456
654321
098765
I attempted to use the following after seeing something similar on another question, but the user didn't leave an explanation, so I'm not sure how the wildcard would be handled:
find . -name "*.csv" -type f | xargs sed -i -e '/*,/d'
Thank you for any help you can offer.
METHOD 1:
If it's always the 2nd column you want, you can do this with awk -- this command is actually splitting the rows on the whitespace rather than the comma, so it gets your second column -- the numbers, but without the leading space:
awk '{print $2}' < whatever.csv
METHOD 2:
Or to get everything after the comma (including the space):
sed -e 's/^.*,//g' < whatever.csv
METHOD 3:
If you want to find all of the .csv files and get the output of all of them together, you can do:
sed -e 's/^.*,//g' `find . -name '*.csv' -print`
METHOD 4:
Or the same way you were starting to -- with find and xargs:
find . -name '*.csv' -type f -print | xargs sed -e 's/^.*,//'
METHOD 5:
Making all of the .csv files into .txt files, processed in the way described above, you can make a brief shell script. Like this:
Create a script "bla.sh":
#!/bin/sh
for infile in `find . -name '*.csv' -print` ; do
outfile=`echo $infile | sed -e 's/.csv/.txt/'`
echo "$infile --> $outfile"
sed -e 's/^.*,//g' < $infile > $outfile
done
Make it executable by typing this:
chmod 755 bla.sh
Then run it:
./bla.sh
This will create a .txt output file with everything after the comma for each .csv input file.
ALTERNATE METHOD 5:
Or if you need them to be named .csv, the script could be updated like this -- this just makes an output file named "file-new.csv" for each input file named "file.csv":
#!/bin/sh
for infile in `find . -name '*.csv' -print` ; do
outfile=`echo $infile | sed -e 's/.csv/-new.csv/'`
echo "$infile --> $outfile"
sed -e 's/^.*,//g' < $infile > $outfile
done
Something like this should work for a single file. Let's say the
input is 'yourfile' and you want the output to go to 'outfile'.
sed 's/^.*,//' < yourfile > outfile
The syntax to do a search-and-replace is s/input_pattern/replacement/
The ^ anchors the input pattern to the beginning of the line.
A dot . matches any single character; .* matches a string of zero or more of any character.
The , matches the comma.
The replacement pattern is empty, so whatever matched the input_pattern
will be removed.

Sed replacing last comma fails

I'm working on a sed script that takes a bunch of lines and turns them into an argument list for matlab (single quoted, comma separated).
It's working well so far:
[script to generate list] | sed -n "s#\(.*$\)#'\1',#p#" | tr '\n' ' '
But this leaves me with a trailing comma.
By testing, I can remove it with
[list of comma separated values] | sed -n 's#,$##p#'
but, when putting it all together:
[script to generate list] | sed -n "s#\(.*$\)#'\1',#;s#,$##p#" | tr '\n' ' '
Outputs nothing.
I feel like it has something to do with not having a p in the first line of the sed script, but I don't want it to print those values, I want them sent to the next line in the script (isn't that the default?)
Edit:
[script to generate list] Outputs a list of directories, for example:
./work/matlab_stun_gun/tex/fullTest.pdf
./Downloads/Howfar(tetra2) fixed.pdf
./work/savdocs/win_tests/tex/texReport.pdf
./Downloads/AcademicAudit.pdf
./work/matlab_stun_gun/report.pdf
./Downloads/PMB_4DVMC.pdf
./work/savdocs/win_tests/tex/mouseHeatMap.pdf
./Downloads/Geometry.pdf
./work/savdocs/win_tests/tex/mouseHeatMap.pdf
./work/matlab_stun_gun/tex/fullTest.pdf
The list generator is just find . -name "*.pdf" | pickl -n 10, adjusted for file type/ number etc. This is going to become a general purpose script.
Expected output would be :
'./work/savdocs/win_tests/tex/mClickss.pdf', './Downloads/Howfar(tetra2) fixed.pdf', './Downloads/MedPhys_defDOSXYZ.pdf', './Downloads/MedPhys_defDOSXYZ.pdf', './report.pdf', './work/savdocs/win_tests/tex/cSwitchs.pdf', './tex/zoomIn.pdf', './tex/fullTest.pdf', './temp/tex/zoomIn.pdf', './tex/zoomIn.pdf'
(Note the lack of trailing comma)
You are experiencing a multi-faceted problem here, in the sense that each of your attempts has something wrong with it.
Starting with [list of comma separated values] | sed -n 's#,$##p#', keep in mind that tr effectively makes your separator ', ' (comma-space) instead of just ',' comma. This means that you will output nothing from the second sed expression. You can fix that by matching with sed -n 's#, $##p#'. If you insist on using the -n flag, that is the correct solution. In full:
[script to generate list] | \
sed -n "s#\(.*$\)#'\1',#p#" | \
tr '\n' ' ' | \
sed -n 's#, $##p#'
The problem with your combination attempt, [script to generate list] | sed -n "s#\(.*$\)#'\1',#;s#,$##p#" | tr '\n' ' ', is that you need to apply tr before you remove the trailing commas. Even if this were to print anything, you would be adding a comma, stripping it off immediately on each line, and then replacing newlines with spaces. The correct order is already shown above.
Multiple commands in sed should be specified using the -e flag. They pipe the result of one command into another, equivalently to using pipes, but much more efficiently. To get sed -n "s#\(.*$\)#'\1',#;s#,$##p#" to print, rephrase it like:
sed -n -e "s#\(.*$\)#'\1',#" -e "s#, $##p#"
This is of course going to strip off the commas as soon as you add them to each line, but it shows the correct syntax for doing so.
Further Improvements
You probably don't need to use the -n flag for sed (and consequently) the /p/ flag for the s command. The -n flag is only useful if you only want to print matches, but you want to print everything, so it does not apply to you.
You also don't need an explicit capture group since you can use the \0 replacement to get the entire match, not just the group. Here is an example:
[script to generate list] | sed "s/.*/'\0'" | tr '\n' ' ' | sed 's/, $//'
Finally, there are alternatives to removing the trailing bits of the string without starting a subprocess, especially since you are already enclosing your expression in $(...):
RESULT=$([script to generate list] | sed "s/.*/'\0'" | tr '\n' ' ')
RESULT=${RESULT%, }
OR
RESULT=${RESULT::-2}

How to inject a line feed to replace a delimiter

/usr/bin/sed 's/,/\\n/g' comma-delimited.txt > newline-separated.txt
This doesn't work for me. I just get the ',' removed but the tokens are now just not delimited.
You must have an older version of sed, so you need to put a literal LF char in your substitution, i.e.
/usr/bin/sed 's/,/
/g' comma-delimited.txt > newline-separated.txt
You may even need to escape the LF, so make sure there are no white space chars after the last char '\'
/usr/bin/sed 's/,/\
/g' comma-delimited.txt > newline-separated.txt
This might work for you:
echo a,b,c,d,e | sed 'G;:a;s/,\(.*\(.\)\)/\2\1/;ta;s/.$//'
a
b
c
d
e
Explanation:
Appends a newline to the pattern space. G
Substitute ,'s with the last character in the pattern space i.e. the \n :a;s/,\(.*\(.\)\)/\2\1/;ta
Remove the newline. s/.$//
I tried the following, looks clumsy but does the work. Easy to understand. I use tr to do the replacement of the placeholder §. Only caveat is the placeholder, must be something NOT in the string(s).
ps -fu $USER | grep java | grep DML| sed -e "s/ -/§ -/g" | tr "§" "\n"
will give you an indented output of the commandline. DML is just some servername.
on AIX7 answer #3 worked well:
I need to insert a newline at the beginning of a paragraph so I can do grep -p to filter for 'mksysb' in the resulting 'stanza'
lsnim -l | /usr/bin/sed 's/^[a-zA-Z/\^J&/'
(actually the initial line had an escaped newline:
lsnim -l | /usr/bin/sed 's/^[a-zA-Z/\
&/')
recalling the command showed the ^J syntax ...

How can sed replace "\ " (backslash + space)?

In a bash script, files with spaces show up as "File\ with\ spaces.txt" and I want to substitute those slashed-spaces with either _ or +.
How can I tell sed to do that? I had no success using;
$1=~/File\ with\ spaces.txt
ext=$1
web=$(echo "$ext" | sed 's/\ /+/')
I'm open to suggestions if there's a better way than through sed.
[EDIT]: Foo Bah's solution works well, but it substitutes only the first space because the text following it is treated as arguments rather than part of the $1. Any way around this?
sed 's/\\\\ /+/';
\\\\ evaluates to a \\ at the shell level, and then into a literal \ within sed.
Sed recognises \ as space just fine:
bee#i20 ~ $ echo file\ 123 | sed 's/\ /+/'
file+123
Your bash script syntax is all wrong, though.
Not sure what you were trying to do with the script, but here is an example of replacing spaces with +:
ext=~/File\ with\ spaces.txt
web=`echo "$ext" | sed 's/\ /+/g'`
echo $web
Upd:
Oh, and you need the g flag to replace all occurences of space, not only the first one. Fixed above.
you want to escape the slash:
web=$(echo "$ext" | sed 's/\\ /_/g')
single quotes are your friend
the following should be used with single quoted args for $1 and $2
#!/bin/bash
ESCAPE='\\'
if [ $# -ne 2 ];then
echo "$0 <TO_ESCAPE> <IN_STRING>"
echo args should be in single quotes!!
exit 1
fi
TO_ESCAPE="${1}"
IN_STRING="${2}"
if [ ${TO_ESCAPE} = '\' ];then
TO_ESCAPE='\\'
fi
echo "${IN_STRING}" | sed "s/${TO_ESCAPE}/${ESCAPE}${TO_ESCAPE}/g"